168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)/* -*- Mode: C; c-basic-offset:8 ; indent-tabs-mode:t -*- */
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/*
3ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch * Linux usbfs backend for libusbx
4ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch * Copyright © 2007-2009 Daniel Drake <dsd@gentoo.org>
5ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch * Copyright © 2001 Johannes Erdfelt <johannes@erdfelt.com>
6ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch * Copyright © 2013 Nathan Hjelm <hjelmn@mac.com>
7ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch * Copyright © 2012-2013 Hans de Goede <hdegoede@redhat.com>
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * This library is free software; you can redistribute it and/or
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * modify it under the terms of the GNU Lesser General Public
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * License as published by the Free Software Foundation; either
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * version 2.1 of the License, or (at your option) any later version.
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * This library is distributed in the hope that it will be useful,
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * but WITHOUT ANY WARRANTY; without even the implied warranty of
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Lesser General Public License for more details.
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * You should have received a copy of the GNU Lesser General Public
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * License along with this library; if not, write to the Free Software
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
24ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch#include "config.h"
25ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
26ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch#include <assert.h>
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <ctype.h>
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <dirent.h>
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <errno.h>
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <fcntl.h>
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <poll.h>
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <stdio.h>
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <stdlib.h>
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <string.h>
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <sys/ioctl.h>
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <sys/stat.h>
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <sys/types.h>
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <sys/utsname.h>
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <unistd.h>
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "libusb.h"
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "libusbi.h"
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "linux_usbfs.h"
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/* sysfs vs usbfs:
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * opening a usbfs node causes the device to be resumed, so we attempt to
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * avoid this during enumeration.
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * sysfs allows us to read the kernel's in-memory copies of device descriptors
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * and so forth, avoiding the need to open the device:
51ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch *  - The binary "descriptors" file contains all config descriptors since
52ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch *    2.6.26, commit 217a9081d8e69026186067711131b77f0ce219ed
53ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch *  - The binary "descriptors" file was added in 2.6.23, commit
54ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch *    69d42a78f935d19384d1f6e4f94b65bb162b36df, but it only contains the
55ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch *    active config descriptors
56ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch *  - The "busnum" file was added in 2.6.22, commit
57ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch *    83f7d958eab2fbc6b159ee92bf1493924e1d0f72
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *  - The "devnum" file has been present since pre-2.6.18
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *  - the "bConfigurationValue" file has been present since pre-2.6.18
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * If we have bConfigurationValue, busnum, and devnum, then we can determine
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * the active configuration without having to open the usbfs node in RDWR mode.
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * The busnum file is important as that is the only way we can relate sysfs
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * devices to usbfs nodes.
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *
66ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch * If we also have all descriptors, we can obtain the device descriptor and
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * configuration without touching usbfs at all.
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/* endianness for multi-byte fields:
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Descriptors exposed by usbfs have the multi-byte fields in the device
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * descriptor as host endian. Multi-byte fields in the other descriptors are
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * bus-endian. The kernel documentation says otherwise, but it is wrong.
75ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch *
76ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch * In sysfs all descriptors are bus-endian.
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static const char *usbfs_path = NULL;
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
81eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch/* use usbdev*.* device names in /dev instead of the usbfs bus directories */
82eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochstatic int usbdev_names = 0;
83eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/* Linux 2.6.32 adds support for a bulk continuation URB flag. this basically
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * allows us to mark URBs as being part of a specific logical transfer when
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * we submit them to the kernel. then, on any error except a cancellation, all
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * URBs within that transfer will be cancelled and no more URBs will be
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * accepted for the transfer, meaning that no more data can creep in.
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * The BULK_CONTINUATION flag must be set on all URBs within a bulk transfer
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * (in either direction) except the first.
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * For IN transfers, we must also set SHORT_NOT_OK on all URBs except the
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * last; it means that the kernel should treat a short reply as an error.
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * For OUT transfers, SHORT_NOT_OK must not be set. it isn't needed (OUT
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * transfers can't be short unless there's already some sort of error), and
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * setting this flag is disallowed (a kernel with USB debugging enabled will
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * reject such URBs).
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int supports_flag_bulk_continuation = -1;
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
101eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch/* Linux 2.6.31 fixes support for the zero length packet URB flag. This
102eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch * allows us to mark URBs that should be followed by a zero length data
103eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch * packet, which can be required by device- or class-specific protocols.
104eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch */
105eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochstatic int supports_flag_zero_packet = -1;
106eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/* clock ID for monotonic clock, as not all clock sources are available on all
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * systems. appropriate choice made at initialization time. */
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static clockid_t monotonic_clkid = -1;
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
111ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch/* Linux 2.6.22 (commit 83f7d958eab2fbc6b159ee92bf1493924e1d0f72) adds a busnum
112ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch * to sysfs, so we can relate devices. This also implies that we can read
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * the active configuration through bConfigurationValue */
114ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdochstatic int sysfs_can_relate_devices = -1;
115ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
116ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch/* Linux 2.6.26 (commit 217a9081d8e69026186067711131b77f0ce219ed) adds all
117ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch * config descriptors (rather then just the active config) to the sysfs
118ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch * descriptors file, so from then on we can use them. */
119ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdochstatic int sysfs_has_descriptors = -1;
120ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
121ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch/* how many times have we initted (and not exited) ? */
122ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdochstatic volatile int init_count = 0;
123ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
12468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)/* Serialize hotplug start/stop */
12568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)usbi_mutex_static_t linux_hotplug_startstop_lock = USBI_MUTEX_INITIALIZER;
12668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)/* Serialize scan-devices, event-thread, and poll */
127ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdochusbi_mutex_static_t linux_hotplug_lock = USBI_MUTEX_INITIALIZER;
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
129ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdochstatic int linux_start_event_monitor(void);
130ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdochstatic int linux_stop_event_monitor(void);
131ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdochstatic int linux_scan_devices(struct libusb_context *ctx);
132ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdochstatic int sysfs_scan_device(struct libusb_context *ctx, const char *devname);
133ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdochstatic int detach_kernel_driver_and_claim(struct libusb_device_handle *, int);
134ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
135ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch#if !defined(USE_UDEV)
136ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdochstatic int linux_default_scan_devices (struct libusb_context *ctx);
137ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch#endif
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)struct linux_device_priv {
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	char *sysfs_dir;
141ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	unsigned char *descriptors;
142ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	int descriptors_len;
143ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	int active_config; /* cache val for !sysfs_can_relate_devices  */
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)struct linux_device_handle_priv {
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	int fd;
148ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	uint32_t caps;
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)enum reap_action {
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	NORMAL = 0,
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	/* submission failed after the first URB, so await cancellation/completion
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	 * of all the others */
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	SUBMIT_FAILED,
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	/* cancelled by user or timeout */
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	CANCELLED,
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	/* completed multi-URB transfer in non-final URB */
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	COMPLETED_EARLY,
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	/* one or more urbs encountered a low-level error */
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	ERROR,
1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)struct linux_transfer_priv {
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	union {
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		struct usbfs_urb *urbs;
1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		struct usbfs_urb **iso_urbs;
1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	};
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	enum reap_action reap_action;
1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	int num_urbs;
175ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	int num_retired;
1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	enum libusb_transfer_status reap_status;
1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	/* next iso packet in user-supplied transfer to be populated */
1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	int iso_packet_offset;
1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
182ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdochstatic int _get_usbfs_fd(struct libusb_device *dev, mode_t mode, int silent)
1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){
184ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	struct libusb_context *ctx = DEVICE_CTX(dev);
185ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	char path[PATH_MAX];
186ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	int fd;
187ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
188eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch	if (usbdev_names)
189eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch		snprintf(path, PATH_MAX, "%s/usbdev%d.%d",
190eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch			usbfs_path, dev->bus_number, dev->device_address);
191eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch	else
192eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch		snprintf(path, PATH_MAX, "%s/%03d/%03d",
193eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch			usbfs_path, dev->bus_number, dev->device_address);
194ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
195ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	fd = open(path, mode);
196ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	if (fd != -1)
197ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		return fd; /* Success */
198ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
199ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	if (!silent) {
200ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		usbi_err(ctx, "libusbx couldn't open USB device %s: %s",
201ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch			 path, strerror(errno));
202ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		if (errno == EACCES && mode == O_RDWR)
203ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch			usbi_err(ctx, "libusbx requires write access to USB "
204ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch				      "device nodes.");
205ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	}
206ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
207ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	if (errno == EACCES)
208ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		return LIBUSB_ERROR_ACCESS;
209ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	if (errno == ENOENT)
210ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		return LIBUSB_ERROR_NO_DEVICE;
211ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	return LIBUSB_ERROR_IO;
2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static struct linux_device_priv *_device_priv(struct libusb_device *dev)
2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){
2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	return (struct linux_device_priv *) dev->os_priv;
2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static struct linux_device_handle_priv *_device_handle_priv(
2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	struct libusb_device_handle *handle)
2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){
2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	return (struct linux_device_handle_priv *) handle->os_priv;
2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
225eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch/* check dirent for a /dev/usbdev%d.%d name
226eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch * optionally return bus/device on success */
227eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochstatic int _is_usbdev_entry(struct dirent *entry, int *bus_p, int *dev_p)
228eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch{
229eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch	int busnum, devnum;
230eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
231eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch	if (sscanf(entry->d_name, "usbdev%d.%d", &busnum, &devnum) != 2)
232eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch		return 0;
233eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
234eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch	usbi_dbg("found: %s", entry->d_name);
235eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch	if (bus_p != NULL)
236eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch		*bus_p = busnum;
237eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch	if (dev_p != NULL)
238eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch		*dev_p = devnum;
239eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch	return 1;
240eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
241eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int check_usb_vfs(const char *dirname)
2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){
2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	DIR *dir;
2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	struct dirent *entry;
2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	int found = 0;
2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	dir = opendir(dirname);
2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	if (!dir)
2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		return 0;
2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	while ((entry = readdir(dir)) != NULL) {
2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		if (entry->d_name[0] == '.')
2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)			continue;
2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		/* We assume if we find any files that it must be the right place */
2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		found = 1;
2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		break;
2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	}
2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	closedir(dir);
2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	return found;
2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static const char *find_usbfs_path(void)
2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){
2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	const char *path = "/dev/bus/usb";
2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	const char *ret = NULL;
2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	if (check_usb_vfs(path)) {
2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		ret = path;
2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	} else {
2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		path = "/proc/bus/usb";
2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		if (check_usb_vfs(path))
2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)			ret = path;
2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	}
2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
278eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch	/* look for /dev/usbdev*.* if the normal places fail */
279eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch	if (ret == NULL) {
280eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch		struct dirent *entry;
281eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch		DIR *dir;
282eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
283eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch		path = "/dev";
284eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch		dir = opendir(path);
285eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch		if (dir != NULL) {
286eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch			while ((entry = readdir(dir)) != NULL) {
287eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch				if (_is_usbdev_entry(entry, NULL, NULL)) {
288eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch					/* found one; that's enough */
289eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch					ret = path;
290eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch					usbdev_names = 1;
291eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch					break;
292eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch				}
293eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch			}
294eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch			closedir(dir);
295eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch		}
296eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch	}
297eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
298eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch	if (ret != NULL)
299eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch		usbi_dbg("found usbfs at %s", ret);
300eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	return ret;
3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/* the monotonic clock is not usable on all systems (e.g. embedded ones often
3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * seem to lack it). fall back to REALTIME if we have to. */
3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static clockid_t find_monotonic_clock(void)
3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){
308eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#ifdef CLOCK_MONOTONIC
3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	struct timespec ts;
3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	int r;
3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	/* Linux 2.6.28 adds CLOCK_MONOTONIC_RAW but we don't use it
3135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	 * because it's not available through timerfd */
3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	r = clock_gettime(CLOCK_MONOTONIC, &ts);
3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	if (r == 0)
3165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		return CLOCK_MONOTONIC;
3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	usbi_dbg("monotonic clock doesn't work, errno %d", errno);
3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	return CLOCK_REALTIME;
3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
323eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochstatic int kernel_version_ge(int major, int minor, int sublevel)
3245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){
3255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	struct utsname uts;
326eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch	int atoms, kmajor, kminor, ksublevel;
3275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	if (uname(&uts) < 0)
3295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		return -1;
330eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch	atoms = sscanf(uts.release, "%d.%d.%d", &kmajor, &kminor, &ksublevel);
3315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	if (atoms < 1)
3325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		return -1;
3335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
334eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch	if (kmajor > major)
3355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		return 1;
336eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch	if (kmajor < major)
3375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		return 0;
3385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
339eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch	/* kmajor == major */
3405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	if (atoms < 2)
341eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch		return 0 == minor && 0 == sublevel;
342eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch	if (kminor > minor)
343eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch		return 1;
344eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch	if (kminor < minor)
3455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		return 0;
3465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
347eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch	/* kminor == minor */
348eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch	if (atoms < 3)
349eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch		return 0 == sublevel;
3505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
351eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch	return ksublevel >= sublevel;
3525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int op_init(struct libusb_context *ctx)
3555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){
3565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	struct stat statbuf;
3575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	int r;
3585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	usbfs_path = find_usbfs_path();
3605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	if (!usbfs_path) {
3615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		usbi_err(ctx, "could not find usbfs");
3625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		return LIBUSB_ERROR_OTHER;
3635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	}
3645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	if (monotonic_clkid == -1)
3665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		monotonic_clkid = find_monotonic_clock();
3675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	if (supports_flag_bulk_continuation == -1) {
369eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch		/* bulk continuation URB flag available from Linux 2.6.32 */
370eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch		supports_flag_bulk_continuation = kernel_version_ge(2,6,32);
3715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		if (supports_flag_bulk_continuation == -1) {
3725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)			usbi_err(ctx, "error checking for bulk continuation support");
3735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)			return LIBUSB_ERROR_OTHER;
3745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		}
3755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	}
3765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	if (supports_flag_bulk_continuation)
3785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		usbi_dbg("bulk continuation flag supported");
3795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
380eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch	if (-1 == supports_flag_zero_packet) {
381eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch		/* zero length packet URB flag fixed since Linux 2.6.31 */
382eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch		supports_flag_zero_packet = kernel_version_ge(2,6,31);
383eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch		if (-1 == supports_flag_zero_packet) {
384eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch			usbi_err(ctx, "error checking for zero length packet support");
385eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch			return LIBUSB_ERROR_OTHER;
386eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch		}
387eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch	}
388eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
389eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch	if (supports_flag_zero_packet)
390eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch		usbi_dbg("zero length packet flag supported");
391eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
392ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	if (-1 == sysfs_has_descriptors) {
393ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		/* sysfs descriptors has all descriptors since Linux 2.6.26 */
394ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		sysfs_has_descriptors = kernel_version_ge(2,6,26);
395ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		if (-1 == sysfs_has_descriptors) {
396ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch			usbi_err(ctx, "error checking for sysfs descriptors");
397ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch			return LIBUSB_ERROR_OTHER;
398ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		}
399ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	}
4005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
401ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	if (-1 == sysfs_can_relate_devices) {
402ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		/* sysfs has busnum since Linux 2.6.22 */
403ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		sysfs_can_relate_devices = kernel_version_ge(2,6,22);
404ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		if (-1 == sysfs_can_relate_devices) {
405ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch			usbi_err(ctx, "error checking for sysfs busnum");
406ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch			return LIBUSB_ERROR_OTHER;
4075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		}
408ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	}
4095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
410ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	if (sysfs_can_relate_devices || sysfs_has_descriptors) {
411ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		r = stat(SYSFS_DEVICE_PATH, &statbuf);
412ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		if (r != 0 || !S_ISDIR(statbuf.st_mode)) {
413ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch			usbi_warn(ctx, "sysfs not mounted");
414ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch			sysfs_can_relate_devices = 0;
415ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch			sysfs_has_descriptors = 0;
416ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		}
417ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	}
4185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
419ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	if (sysfs_can_relate_devices)
420ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		usbi_dbg("sysfs can relate devices");
4215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
422ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	if (sysfs_has_descriptors)
423ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		usbi_dbg("sysfs has complete descriptors");
424ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
42568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)	usbi_mutex_static_lock(&linux_hotplug_startstop_lock);
426ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	r = LIBUSB_SUCCESS;
427ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	if (init_count == 0) {
428ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		/* start up hotplug event handler */
429ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		r = linux_start_event_monitor();
430ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	}
431ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	if (r == LIBUSB_SUCCESS) {
432ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		r = linux_scan_devices(ctx);
433ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		if (r == LIBUSB_SUCCESS)
434ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch			init_count++;
435ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		else if (init_count == 0)
436ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch			linux_stop_event_monitor();
437ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	} else
438ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		usbi_err(ctx, "error starting hotplug event monitor");
43968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)	usbi_mutex_static_unlock(&linux_hotplug_startstop_lock);
4405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
441ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	return r;
442ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch}
4435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
444ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdochstatic void op_exit(void)
445ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch{
44668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)	usbi_mutex_static_lock(&linux_hotplug_startstop_lock);
447ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	assert(init_count != 0);
448ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	if (!--init_count) {
449ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		/* tear down event handler */
450ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		(void)linux_stop_event_monitor();
4515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	}
45268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)	usbi_mutex_static_unlock(&linux_hotplug_startstop_lock);
453ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch}
4545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
455ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdochstatic int linux_start_event_monitor(void)
456ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch{
457ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch#if defined(USE_UDEV)
458ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	return linux_udev_start_event_monitor();
459ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch#else
460ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	return linux_netlink_start_event_monitor();
461ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch#endif
4625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
464ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdochstatic int linux_stop_event_monitor(void)
4655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){
466ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch#if defined(USE_UDEV)
467ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	return linux_udev_stop_event_monitor();
468ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch#else
469ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	return linux_netlink_stop_event_monitor();
470ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch#endif
471ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch}
4725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
473ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdochstatic int linux_scan_devices(struct libusb_context *ctx)
474ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch{
47568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)	int ret;
47668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
47768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)	usbi_mutex_static_lock(&linux_hotplug_lock);
47868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
479ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch#if defined(USE_UDEV)
48068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)	ret = linux_udev_scan_devices(ctx);
481ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch#else
48268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)	ret = linux_default_scan_devices(ctx);
483ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch#endif
48468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
48568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)	usbi_mutex_static_unlock(&linux_hotplug_lock);
48668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
48768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)	return ret;
488ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch}
489ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
490ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdochstatic void op_hotplug_poll(void)
491ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch{
492ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch#if defined(USE_UDEV)
493ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	linux_udev_hotplug_poll();
494ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch#else
495ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	linux_netlink_hotplug_poll();
496ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch#endif
4975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int _open_sysfs_attr(struct libusb_device *dev, const char *attr)
5005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){
5015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	struct linux_device_priv *priv = _device_priv(dev);
5025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	char filename[PATH_MAX];
5035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	int fd;
5045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	snprintf(filename, PATH_MAX, "%s/%s/%s",
5065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		SYSFS_DEVICE_PATH, priv->sysfs_dir, attr);
5075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	fd = open(filename, O_RDONLY);
5085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	if (fd < 0) {
5095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		usbi_err(DEVICE_CTX(dev),
5105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)			"open %s failed ret=%d errno=%d", filename, fd, errno);
5115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		return LIBUSB_ERROR_IO;
5125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	}
5135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	return fd;
5155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/* Note only suitable for attributes which always read >= 0, < 0 is error */
5185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int __read_sysfs_attr(struct libusb_context *ctx,
5195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	const char *devname, const char *attr)
5205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){
5215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	char filename[PATH_MAX];
5225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	FILE *f;
5235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	int r, value;
5245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	snprintf(filename, PATH_MAX, "%s/%s/%s", SYSFS_DEVICE_PATH,
5265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		 devname, attr);
5275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	f = fopen(filename, "r");
5285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	if (f == NULL) {
5295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		if (errno == ENOENT) {
5305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)			/* File doesn't exist. Assume the device has been
5315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)			   disconnected (see trac ticket #70). */
5325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)			return LIBUSB_ERROR_NO_DEVICE;
5335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		}
5345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		usbi_err(ctx, "open %s failed errno=%d", filename, errno);
5355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		return LIBUSB_ERROR_IO;
5365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	}
5375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	r = fscanf(f, "%d", &value);
5395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	fclose(f);
5405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	if (r != 1) {
5415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		usbi_err(ctx, "fscanf %s returned %d, errno=%d", attr, r, errno);
5425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		return LIBUSB_ERROR_NO_DEVICE; /* For unplug race (trac #70) */
5435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	}
5445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	if (value < 0) {
5455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		usbi_err(ctx, "%s contains a negative value", filename);
5465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		return LIBUSB_ERROR_IO;
5475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	}
5485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	return value;
5505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int op_get_device_descriptor(struct libusb_device *dev,
5535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	unsigned char *buffer, int *host_endian)
5545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){
5555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	struct linux_device_priv *priv = _device_priv(dev);
5565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
557ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	*host_endian = sysfs_has_descriptors ? 0 : 1;
558ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	memcpy(buffer, priv->descriptors, DEVICE_DESC_LENGTH);
559ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
5605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	return 0;
5615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/* read the bConfigurationValue for a device */
5645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int sysfs_get_active_config(struct libusb_device *dev, int *config)
5655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){
5665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	char *endptr;
5675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	char tmp[4] = {0, 0, 0, 0};
5685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	long num;
5695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	int fd;
5705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	ssize_t r;
5715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	fd = _open_sysfs_attr(dev, "bConfigurationValue");
5735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	if (fd < 0)
5745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		return fd;
5755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	r = read(fd, tmp, sizeof(tmp));
5775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	close(fd);
5785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	if (r < 0) {
5795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		usbi_err(DEVICE_CTX(dev),
5805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)			"read bConfigurationValue failed ret=%d errno=%d", r, errno);
5815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		return LIBUSB_ERROR_IO;
5825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	} else if (r == 0) {
583eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch		usbi_dbg("device unconfigured");
5845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		*config = -1;
5855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		return 0;
5865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	}
5875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	if (tmp[sizeof(tmp) - 1] != 0) {
5895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		usbi_err(DEVICE_CTX(dev), "not null-terminated?");
5905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		return LIBUSB_ERROR_IO;
5915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	} else if (tmp[0] == 0) {
5925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		usbi_err(DEVICE_CTX(dev), "no configuration value?");
5935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		return LIBUSB_ERROR_IO;
5945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	}
5955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	num = strtol(tmp, &endptr, 10);
5975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	if (endptr == tmp) {
5985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		usbi_err(DEVICE_CTX(dev), "error converting '%s' to integer", tmp);
5995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		return LIBUSB_ERROR_IO;
6005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	}
6015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	*config = (int) num;
6035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	return 0;
6045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
606ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdochint linux_get_device_address (struct libusb_context *ctx, int detached,
607ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	uint8_t *busnum, uint8_t *devaddr,const char *dev_node,
608ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	const char *sys_name)
6095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){
61068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)	int sysfs_attr;
61168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
612ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	usbi_dbg("getting address for device: %s detached: %d", sys_name, detached);
613ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	/* can't use sysfs to read the bus and device number if the
614ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	 * device has been detached */
615ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	if (!sysfs_can_relate_devices || detached || NULL == sys_name) {
616ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		if (NULL == dev_node) {
617ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch			return LIBUSB_ERROR_OTHER;
618ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		}
6195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
620ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		/* will this work with all supported kernel versions? */
621ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		if (!strncmp(dev_node, "/dev/bus/usb", 12)) {
622ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch			sscanf (dev_node, "/dev/bus/usb/%hhd/%hhd", busnum, devaddr);
623ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		} else if (!strncmp(dev_node, "/proc/bus/usb", 13)) {
624ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch			sscanf (dev_node, "/proc/bus/usb/%hhd/%hhd", busnum, devaddr);
625ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		}
6265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
627ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		return LIBUSB_SUCCESS;
6285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	}
6295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
630ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	usbi_dbg("scan %s", sys_name);
631ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
63268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)	sysfs_attr = __read_sysfs_attr(ctx, sys_name, "busnum");
63368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)	if (0 > sysfs_attr)
63468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)		return sysfs_attr;
63568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)	if (sysfs_attr > 255)
63668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)		return LIBUSB_ERROR_INVALID_PARAM;
63768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)	*busnum = (uint8_t) sysfs_attr;
63868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
63968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)	sysfs_attr = __read_sysfs_attr(ctx, sys_name, "devnum");
64068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)	if (0 > sysfs_attr)
64168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)		return sysfs_attr;
64268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)	if (sysfs_attr > 255)
64368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)		return LIBUSB_ERROR_INVALID_PARAM;
644ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
64568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)	*devaddr = (uint8_t) sysfs_attr;
646ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
647ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	usbi_dbg("bus=%d dev=%d", *busnum, *devaddr);
648ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
649ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	return LIBUSB_SUCCESS;
6505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
652ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch/* Return offset of the next descriptor with the given type */
653ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdochstatic int seek_to_next_descriptor(struct libusb_context *ctx,
654ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	uint8_t descriptor_type, unsigned char *buffer, int size)
6555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){
656ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	struct usb_descriptor_header header;
657ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	int i;
6585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
659ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	for (i = 0; size >= 0; i += header.bLength, size -= header.bLength) {
660ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		if (size == 0)
661ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch			return LIBUSB_ERROR_NOT_FOUND;
6625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
663ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		if (size < 2) {
664ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch			usbi_err(ctx, "short descriptor read %d/2", size);
665ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch			return LIBUSB_ERROR_IO;
666ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		}
667ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		usbi_parse_descriptor(buffer + i, "bb", &header, 0);
6685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
669ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		if (i && header.bDescriptorType == descriptor_type)
670ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch			return i;
671ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	}
672ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	usbi_err(ctx, "bLength overflow by %d bytes", -size);
673ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	return LIBUSB_ERROR_IO;
674ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch}
6755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
676ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch/* Return offset to next config */
677ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdochstatic int seek_to_next_config(struct libusb_context *ctx,
678ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	unsigned char *buffer, int size)
679ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch{
680ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	struct libusb_config_descriptor config;
6815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
682ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	if (size == 0)
6835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		return LIBUSB_ERROR_NOT_FOUND;
684ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
685ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	if (size < LIBUSB_DT_CONFIG_SIZE) {
686ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		usbi_err(ctx, "short descriptor read %d/%d",
687ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch			 size, LIBUSB_DT_CONFIG_SIZE);
688ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		return LIBUSB_ERROR_IO;
6895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	}
6905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
691ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	usbi_parse_descriptor(buffer, "bbwbbbbb", &config, 0);
692ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	if (config.bDescriptorType != LIBUSB_DT_CONFIG) {
693ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		usbi_err(ctx, "descriptor is not a config desc (type 0x%02x)",
694ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch			 config.bDescriptorType);
6955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		return LIBUSB_ERROR_IO;
6965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	}
6975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
698ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	/*
699ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	 * In usbfs the config descriptors are config.wTotalLength bytes apart,
700ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	 * with any short reads from the device appearing as holes in the file.
701ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	 *
702ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	 * In sysfs wTotalLength is ignored, instead the kernel returns a
703ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	 * config descriptor with verified bLength fields, with descriptors
704ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	 * with an invalid bLength removed.
705ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	 */
706ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	if (sysfs_has_descriptors) {
707ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		int next = seek_to_next_descriptor(ctx, LIBUSB_DT_CONFIG,
708ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch						   buffer, size);
709ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		if (next == LIBUSB_ERROR_NOT_FOUND)
710ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch			next = size;
711ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		if (next < 0)
712ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch			return next;
713ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
714ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		if (next != config.wTotalLength)
715ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch			usbi_warn(ctx, "config length mismatch wTotalLength "
716ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch				  "%d real %d", config.wTotalLength, next);
717ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		return next;
718ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	} else {
719ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		if (config.wTotalLength < LIBUSB_DT_CONFIG_SIZE) {
720ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch			usbi_err(ctx, "invalid wTotalLength %d",
721ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch				 config.wTotalLength);
7225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)			return LIBUSB_ERROR_IO;
723ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		} else if (config.wTotalLength > size) {
724ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch			usbi_warn(ctx, "short descriptor read %d/%d",
725ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch				  size, config.wTotalLength);
726ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch			return size;
727ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		} else
728ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch			return config.wTotalLength;
729ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	}
730ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch}
7315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
732ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdochstatic int op_get_config_descriptor_by_value(struct libusb_device *dev,
733ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	uint8_t value, unsigned char **buffer, int *host_endian)
734ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch{
735ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	struct libusb_context *ctx = DEVICE_CTX(dev);
736ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	struct linux_device_priv *priv = _device_priv(dev);
737ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	unsigned char *descriptors = priv->descriptors;
738ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	int size = priv->descriptors_len;
739ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	struct libusb_config_descriptor *config;
7405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
741ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	*buffer = NULL;
742ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	/* Unlike the device desc. config descs. are always in raw format */
743ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	*host_endian = 0;
7445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
745ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	/* Skip device header */
746ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	descriptors += DEVICE_DESC_LENGTH;
747ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	size -= DEVICE_DESC_LENGTH;
7485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
749ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	/* Seek till the config is found, or till "EOF" */
750ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	while (1) {
751ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		int next = seek_to_next_config(ctx, descriptors, size);
752ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		if (next < 0)
753ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch			return next;
754ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		config = (struct libusb_config_descriptor *)descriptors;
755ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		if (config->bConfigurationValue == value) {
756ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch			*buffer = descriptors;
757ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch			return next;
7585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		}
759ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		size -= next;
760ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		descriptors += next;
7615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	}
7625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
7635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int op_get_active_config_descriptor(struct libusb_device *dev,
7655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	unsigned char *buffer, size_t len, int *host_endian)
7665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){
767ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	int r, config;
768ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	unsigned char *config_desc;
7695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
770ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	if (sysfs_can_relate_devices) {
771ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		r = sysfs_get_active_config(dev, &config);
7725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		if (r < 0)
7735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)			return r;
774ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	} else {
775ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		/* Use cached bConfigurationValue */
776ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		struct linux_device_priv *priv = _device_priv(dev);
777ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		config = priv->active_config;
7785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	}
779ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	if (config == -1)
780ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		return LIBUSB_ERROR_NOT_FOUND;
7815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
782ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	r = op_get_config_descriptor_by_value(dev, config, &config_desc,
783ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch					      host_endian);
784ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	if (r < 0)
785ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		return r;
7865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
787ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	len = MIN(len, r);
788ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	memcpy(buffer, config_desc, len);
789ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	return len;
7905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
7915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int op_get_config_descriptor(struct libusb_device *dev,
7935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	uint8_t config_index, unsigned char *buffer, size_t len, int *host_endian)
7945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){
795ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	struct linux_device_priv *priv = _device_priv(dev);
796ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	unsigned char *descriptors = priv->descriptors;
797ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	int i, r, size = priv->descriptors_len;
7985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
799ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	/* Unlike the device desc. config descs. are always in raw format */
800ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	*host_endian = 0;
8015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
802ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	/* Skip device header */
803ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	descriptors += DEVICE_DESC_LENGTH;
804ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	size -= DEVICE_DESC_LENGTH;
8055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
806ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	/* Seek till the config is found, or till "EOF" */
807ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	for (i = 0; ; i++) {
808ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		r = seek_to_next_config(DEVICE_CTX(dev), descriptors, size);
8095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		if (r < 0)
8105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)			return r;
811ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		if (i == config_index)
812ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch			break;
813ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		size -= r;
814ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		descriptors += r;
8155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	}
8165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
817ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	len = MIN(len, r);
818ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	memcpy(buffer, descriptors, len);
819ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	return len;
8205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
8215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/* send a control message to retrieve active configuration */
8235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int usbfs_get_active_config(struct libusb_device *dev, int fd)
8245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){
8255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	unsigned char active_config = 0;
8265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	int r;
8275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	struct usbfs_ctrltransfer ctrl = {
8295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		.bmRequestType = LIBUSB_ENDPOINT_IN,
8305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		.bRequest = LIBUSB_REQUEST_GET_CONFIGURATION,
8315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		.wValue = 0,
8325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		.wIndex = 0,
8335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		.wLength = 1,
8345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		.timeout = 1000,
8355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		.data = &active_config
8365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	};
8375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	r = ioctl(fd, IOCTL_USBFS_CONTROL, &ctrl);
8395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	if (r < 0) {
8405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		if (errno == ENODEV)
8415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)			return LIBUSB_ERROR_NO_DEVICE;
8425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		/* we hit this error path frequently with buggy devices :( */
8445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		usbi_warn(DEVICE_CTX(dev),
8455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)			"get_configuration failed ret=%d errno=%d", r, errno);
8465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		return LIBUSB_ERROR_IO;
8475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	}
8485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	return active_config;
8505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
8515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int initialize_device(struct libusb_device *dev, uint8_t busnum,
8535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	uint8_t devaddr, const char *sysfs_dir)
8545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){
8555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	struct linux_device_priv *priv = _device_priv(dev);
856ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	struct libusb_context *ctx = DEVICE_CTX(dev);
857ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	int descriptors_size = 512; /* Begin with a 1024 byte alloc */
8585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	int fd, speed;
8595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	ssize_t r;
8605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	dev->bus_number = busnum;
8625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	dev->device_address = devaddr;
8635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	if (sysfs_dir) {
8655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		priv->sysfs_dir = malloc(strlen(sysfs_dir) + 1);
8665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		if (!priv->sysfs_dir)
8675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)			return LIBUSB_ERROR_NO_MEM;
8685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		strcpy(priv->sysfs_dir, sysfs_dir);
8695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		/* Note speed can contain 1.5, in this case __read_sysfs_attr
8715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		   will stop parsing at the '.' and return 1 */
8725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		speed = __read_sysfs_attr(DEVICE_CTX(dev), sysfs_dir, "speed");
8735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		if (speed >= 0) {
8745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)			switch (speed) {
8755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)			case     1: dev->speed = LIBUSB_SPEED_LOW; break;
8765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)			case    12: dev->speed = LIBUSB_SPEED_FULL; break;
8775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)			case   480: dev->speed = LIBUSB_SPEED_HIGH; break;
8785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)			case  5000: dev->speed = LIBUSB_SPEED_SUPER; break;
8795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)			default:
8805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)				usbi_warn(DEVICE_CTX(dev), "Unknown device speed: %d Mbps", speed);
8815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)			}
8825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		}
8835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	}
8845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
885ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	/* cache descriptors in memory */
8865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	if (sysfs_has_descriptors)
887ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		fd = _open_sysfs_attr(dev, "descriptors");
888ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	else
889ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		fd = _get_usbfs_fd(dev, O_RDONLY, 0);
890ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	if (fd < 0)
891ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		return fd;
8925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
893ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	do {
894ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		descriptors_size *= 2;
895ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		priv->descriptors = usbi_reallocf(priv->descriptors,
896ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch						  descriptors_size);
897ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		if (!priv->descriptors) {
898ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch			close(fd);
899ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch			return LIBUSB_ERROR_NO_MEM;
900ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		}
901ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		/* usbfs has holes in the file */
902ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		if (!sysfs_has_descriptors) {
903ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch			memset(priv->descriptors + priv->descriptors_len,
904ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch			       0, descriptors_size - priv->descriptors_len);
905ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		}
906ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		r = read(fd, priv->descriptors + priv->descriptors_len,
907ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch			 descriptors_size - priv->descriptors_len);
908ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		if (r < 0) {
909ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch			usbi_err(ctx, "read descriptor failed ret=%d errno=%d",
910ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch				 fd, errno);
911ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch			close(fd);
912ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch			return LIBUSB_ERROR_IO;
913ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		}
914ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		priv->descriptors_len += r;
915ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	} while (priv->descriptors_len == descriptors_size);
916ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
917ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	close(fd);
9185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
919ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	if (priv->descriptors_len < DEVICE_DESC_LENGTH) {
920ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		usbi_err(ctx, "short descriptor read (%d)",
921ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch			 priv->descriptors_len);
922ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		return LIBUSB_ERROR_IO;
9235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	}
9245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
925ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	if (sysfs_can_relate_devices)
926ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		return LIBUSB_SUCCESS;
9275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
928ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	/* cache active config */
929ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	fd = _get_usbfs_fd(dev, O_RDWR, 1);
9305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	if (fd < 0) {
931ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		/* cannot send a control message to determine the active
932ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		 * config. just assume the first one is active. */
933ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		usbi_warn(ctx, "Missing rw usbfs access; cannot determine "
934ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch			       "active configuration descriptor");
935ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		if (priv->descriptors_len >=
936ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch				(DEVICE_DESC_LENGTH + LIBUSB_DT_CONFIG_SIZE)) {
937ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch			struct libusb_config_descriptor config;
938ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch			usbi_parse_descriptor(
939ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch				priv->descriptors + DEVICE_DESC_LENGTH,
940ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch				"bbwbbbbb", &config, 0);
941ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch			priv->active_config = config.bConfigurationValue;
942ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		} else
943ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch			priv->active_config = -1; /* No config dt */
944ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
945ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		return LIBUSB_SUCCESS;
946ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	}
947ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
948ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	r = usbfs_get_active_config(dev, fd);
949ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	if (r > 0) {
950ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		priv->active_config = r;
951ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		r = LIBUSB_SUCCESS;
952ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	} else if (r == 0) {
953ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		/* some buggy devices have a configuration 0, but we're
954ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		 * reaching into the corner of a corner case here, so let's
955ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		 * not support buggy devices in these circumstances.
956ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		 * stick to the specs: a configuration value of 0 means
957ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		 * unconfigured. */
958ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		usbi_dbg("active cfg 0? assuming unconfigured device");
959ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		priv->active_config = -1;
960ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		r = LIBUSB_SUCCESS;
961ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	} else if (r == LIBUSB_ERROR_IO) {
962ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		/* buggy devices sometimes fail to report their active config.
963ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		 * assume unconfigured and continue the probing */
964ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		usbi_warn(ctx, "couldn't query active configuration, assuming"
965ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch			       " unconfigured");
966ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		priv->active_config = -1;
967ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		r = LIBUSB_SUCCESS;
968ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	} /* else r < 0, just return the error code */
9695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
970ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	close(fd);
971ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	return r;
972ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch}
973ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
974ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdochstatic int linux_get_parent_info(struct libusb_device *dev, const char *sysfs_dir)
975ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch{
976ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	struct libusb_context *ctx = DEVICE_CTX(dev);
977ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	struct libusb_device *it;
978ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	char *parent_sysfs_dir, *tmp;
979ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	int ret, add_parent = 1;
980ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
981ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	/* XXX -- can we figure out the topology when using usbfs? */
982ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	if (NULL == sysfs_dir || 0 == strncmp(sysfs_dir, "usb", 3)) {
983ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		/* either using usbfs or finding the parent of a root hub */
984ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		return LIBUSB_SUCCESS;
985ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	}
986ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
987ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	parent_sysfs_dir = strdup(sysfs_dir);
988ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	if (NULL != (tmp = strrchr(parent_sysfs_dir, '.')) ||
989ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	    NULL != (tmp = strrchr(parent_sysfs_dir, '-'))) {
990ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	        dev->port_number = atoi(tmp + 1);
991ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		*tmp = '\0';
992ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	} else {
993ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		usbi_warn(ctx, "Can not parse sysfs_dir: %s, no parent info",
994ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch			  parent_sysfs_dir);
995ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		free (parent_sysfs_dir);
996ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		return LIBUSB_SUCCESS;
997ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	}
998ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
999ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	/* is the parent a root hub? */
1000ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	if (NULL == strchr(parent_sysfs_dir, '-')) {
1001ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		tmp = parent_sysfs_dir;
1002ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		ret = asprintf (&parent_sysfs_dir, "usb%s", tmp);
1003ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		free (tmp);
1004ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		if (0 > ret) {
1005ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch			return LIBUSB_ERROR_NO_MEM;
10065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		}
10075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	}
10085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1009ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdochretry:
1010ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	/* find the parent in the context */
1011ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	usbi_mutex_lock(&ctx->usb_devs_lock);
1012ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	list_for_each_entry(it, &ctx->usb_devs, list, struct libusb_device) {
1013ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		struct linux_device_priv *priv = _device_priv(it);
1014ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		if (0 == strcmp (priv->sysfs_dir, parent_sysfs_dir)) {
1015ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch			dev->parent_dev = libusb_ref_device(it);
1016ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch			break;
1017ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		}
10185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	}
1019ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	usbi_mutex_unlock(&ctx->usb_devs_lock);
10205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1021ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	if (!dev->parent_dev && add_parent) {
1022ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		usbi_dbg("parent_dev %s not enumerated yet, enumerating now",
1023ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch			 parent_sysfs_dir);
1024ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		sysfs_scan_device(ctx, parent_sysfs_dir);
1025ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		add_parent = 0;
1026ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		goto retry;
10275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	}
10285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1029ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	usbi_dbg("Dev %p (%s) has parent %p (%s) port %d", dev, sysfs_dir,
1030ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		 dev->parent_dev, parent_sysfs_dir, dev->port_number);
10315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1032ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	free (parent_sysfs_dir);
10335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1034ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	return LIBUSB_SUCCESS;
10355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
10365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1037ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdochint linux_enumerate_device(struct libusb_context *ctx,
1038ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	uint8_t busnum, uint8_t devaddr, const char *sysfs_dir)
10395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){
10405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	unsigned long session_id;
10415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	struct libusb_device *dev;
10425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	int r = 0;
10435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	/* FIXME: session ID is not guaranteed unique as addresses can wrap and
10455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	 * will be reused. instead we should add a simple sysfs attribute with
10465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	 * a session ID. */
10475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	session_id = busnum << 8 | devaddr;
10485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	usbi_dbg("busnum %d devaddr %d session_id %ld", busnum, devaddr,
10495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		session_id);
10505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1051ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	if (usbi_get_device_by_session_id(ctx, session_id)) {
1052ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		/* device already exists in the context */
1053ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		usbi_dbg("session_id %ld already exists", session_id);
1054ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		return LIBUSB_SUCCESS;
10555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	}
10565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1057ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	usbi_dbg("allocating new device for %d/%d (session %ld)",
1058ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		 busnum, devaddr, session_id);
1059ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	dev = usbi_alloc_device(ctx, session_id);
1060ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	if (!dev)
1061ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		return LIBUSB_ERROR_NO_MEM;
10625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1063ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	r = initialize_device(dev, busnum, devaddr, sysfs_dir);
1064ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	if (r < 0)
1065ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		goto out;
1066ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	r = usbi_sanitize_device(dev);
1067ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	if (r < 0)
1068ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		goto out;
1069ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
1070ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	r = linux_get_parent_info(dev, sysfs_dir);
1071ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	if (r < 0)
1072ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		goto out;
10735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)out:
1074ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	if (r < 0)
10755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		libusb_unref_device(dev);
1076ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	else
1077ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		usbi_connect_device(dev);
1078ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
10795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	return r;
10805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
10815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1082ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdochvoid linux_hotplug_enumerate(uint8_t busnum, uint8_t devaddr, const char *sys_name)
1083ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch{
1084ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	struct libusb_context *ctx;
1085ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
1086ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	usbi_mutex_static_lock(&active_contexts_lock);
1087ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	list_for_each_entry(ctx, &active_contexts_list, list, struct libusb_context) {
1088ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		linux_enumerate_device(ctx, busnum, devaddr, sys_name);
1089ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	}
1090ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	usbi_mutex_static_unlock(&active_contexts_lock);
1091ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch}
1092ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
109368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)void linux_device_disconnected(uint8_t busnum, uint8_t devaddr, const char *sys_name)
1094ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch{
1095ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	struct libusb_context *ctx;
1096ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	struct libusb_device *dev;
1097ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	unsigned long session_id = busnum << 8 | devaddr;
1098ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
1099ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	usbi_mutex_static_lock(&active_contexts_lock);
1100ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	list_for_each_entry(ctx, &active_contexts_list, list, struct libusb_context) {
1101ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		dev = usbi_get_device_by_session_id (ctx, session_id);
1102ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		if (NULL != dev) {
1103ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch			usbi_disconnect_device (dev);
1104ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		} else {
1105ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch			usbi_dbg("device not found for session %x", session_id);
1106ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		}
1107ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	}
1108ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	usbi_mutex_static_unlock(&active_contexts_lock);
1109ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch}
1110ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
1111ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch#if !defined(USE_UDEV)
1112ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch/* open a bus directory and adds all discovered devices to the context */
1113ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdochstatic int usbfs_scan_busdir(struct libusb_context *ctx, uint8_t busnum)
11145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){
11155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	DIR *dir;
11165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	char dirpath[PATH_MAX];
11175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	struct dirent *entry;
11185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	int r = LIBUSB_ERROR_IO;
11195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	snprintf(dirpath, PATH_MAX, "%s/%03d", usbfs_path, busnum);
11215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	usbi_dbg("%s", dirpath);
11225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	dir = opendir(dirpath);
11235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	if (!dir) {
11245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		usbi_err(ctx, "opendir '%s' failed, errno=%d", dirpath, errno);
11255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		/* FIXME: should handle valid race conditions like hub unplugged
11265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		 * during directory iteration - this is not an error */
11275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		return r;
11285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	}
11295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	while ((entry = readdir(dir))) {
11315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		int devaddr;
11325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		if (entry->d_name[0] == '.')
11345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)			continue;
11355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		devaddr = atoi(entry->d_name);
11375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		if (devaddr == 0) {
11385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)			usbi_dbg("unknown dir entry %s", entry->d_name);
11395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)			continue;
11405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		}
11415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1142ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		if (linux_enumerate_device(ctx, busnum, (uint8_t) devaddr, NULL)) {
11435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)			usbi_dbg("failed to enumerate dir entry %s", entry->d_name);
11445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)			continue;
11455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		}
11465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		r = 0;
11485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	}
11495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	closedir(dir);
11515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	return r;
11525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
11535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1154ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdochstatic int usbfs_get_device_list(struct libusb_context *ctx)
11555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){
11565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	struct dirent *entry;
11575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	DIR *buses = opendir(usbfs_path);
11585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	int r = 0;
11595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	if (!buses) {
11615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		usbi_err(ctx, "opendir buses failed errno=%d", errno);
11625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		return LIBUSB_ERROR_IO;
11635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	}
11645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	while ((entry = readdir(buses))) {
11665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		int busnum;
11675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		if (entry->d_name[0] == '.')
11695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)			continue;
11705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1171eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch		if (usbdev_names) {
1172eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch			int devaddr;
1173eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch			if (!_is_usbdev_entry(entry, &busnum, &devaddr))
1174eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch				continue;
11755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1176ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch			r = linux_enumerate_device(ctx, busnum, (uint8_t) devaddr, NULL);
1177eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch			if (r < 0) {
1178eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch				usbi_dbg("failed to enumerate dir entry %s", entry->d_name);
1179eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch				continue;
1180eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch			}
1181eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch		} else {
1182eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch			busnum = atoi(entry->d_name);
1183eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch			if (busnum == 0) {
1184eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch				usbi_dbg("unknown dir entry %s", entry->d_name);
1185eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch				continue;
1186eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch			}
1187eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
1188ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch			r = usbfs_scan_busdir(ctx, busnum);
1189eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch			if (r < 0)
1190ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch				break;
1191eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch		}
11925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	}
11935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	closedir(buses);
11955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	return r;
11965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1198ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch#endif
11995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1200ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdochstatic int sysfs_scan_device(struct libusb_context *ctx, const char *devname)
12015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){
1202ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	uint8_t busnum, devaddr;
1203ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	int ret;
12045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1205ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	ret = linux_get_device_address (ctx, 0, &busnum, &devaddr, NULL, devname);
1206ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	if (LIBUSB_SUCCESS != ret) {
1207ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		return ret;
1208ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	}
12095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1210ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	return linux_enumerate_device(ctx, busnum & 0xff, devaddr & 0xff,
12115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		devname);
12125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
12135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1214ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch#if !defined(USE_UDEV)
1215ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdochstatic int sysfs_get_device_list(struct libusb_context *ctx)
12165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){
12175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	DIR *devices = opendir(SYSFS_DEVICE_PATH);
12185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	struct dirent *entry;
12195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	int r = LIBUSB_ERROR_IO;
12205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
12215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	if (!devices) {
12225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		usbi_err(ctx, "opendir devices failed errno=%d", errno);
12235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		return r;
12245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	}
12255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
12265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	while ((entry = readdir(devices))) {
12275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		if ((!isdigit(entry->d_name[0]) && strncmp(entry->d_name, "usb", 3))
12285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)				|| strchr(entry->d_name, ':'))
12295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)			continue;
12305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1231ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		if (sysfs_scan_device(ctx, entry->d_name)) {
12325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)			usbi_dbg("failed to enumerate dir entry %s", entry->d_name);
12335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)			continue;
12345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		}
12355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
12365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		r = 0;
12375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	}
12385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
12395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	closedir(devices);
12405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	return r;
12415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
12425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1243ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdochstatic int linux_default_scan_devices (struct libusb_context *ctx)
12445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){
12455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	/* we can retrieve device list and descriptors from sysfs or usbfs.
12465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	 * sysfs is preferable, because if we use usbfs we end up resuming
12475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	 * any autosuspended USB devices. however, sysfs is not available
12485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	 * everywhere, so we need a usbfs fallback too.
12495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	 *
12505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	 * as described in the "sysfs vs usbfs" comment at the top of this
12515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	 * file, sometimes we have sysfs but not enough information to
12525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	 * relate sysfs devices to usbfs nodes.  op_init() determines the
12535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	 * adequacy of sysfs and sets sysfs_can_relate_devices.
12545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	 */
12555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	if (sysfs_can_relate_devices != 0)
1256ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		return sysfs_get_device_list(ctx);
12575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	else
1258ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		return usbfs_get_device_list(ctx);
12595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1260ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch#endif
12615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
12625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int op_open(struct libusb_device_handle *handle)
12635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){
12645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	struct linux_device_handle_priv *hpriv = _device_handle_priv(handle);
1265ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	int r;
12665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1267ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	hpriv->fd = _get_usbfs_fd(handle->dev, O_RDWR, 0);
126868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)	if (hpriv->fd < 0) {
126968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)		if (hpriv->fd == LIBUSB_ERROR_NO_DEVICE) {
127068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)			/* device will still be marked as attached if hotplug monitor thread
127168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)			 * hasn't processed remove event yet */
127268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)			usbi_mutex_static_lock(&linux_hotplug_lock);
127368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)			if (handle->dev->attached) {
127468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)				usbi_dbg("open failed with no device, but device still attached");
127568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)				linux_device_disconnected(handle->dev->bus_number,
127668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)						handle->dev->device_address, NULL);
127768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)			}
127868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)			usbi_mutex_static_unlock(&linux_hotplug_lock);
127968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)		}
1280ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		return hpriv->fd;
128168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)	}
1282ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
1283ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	r = ioctl(hpriv->fd, IOCTL_USBFS_GET_CAPABILITIES, &hpriv->caps);
1284ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	if (r < 0) {
1285ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		if (errno == ENOTTY)
1286ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch			usbi_dbg("getcap not available");
1287ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		else
1288ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch			usbi_err(HANDLE_CTX(handle), "getcap failed (%d)", errno);
1289ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		hpriv->caps = 0;
1290ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		if (supports_flag_zero_packet)
1291ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch			hpriv->caps |= USBFS_CAP_ZERO_PACKET;
1292ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		if (supports_flag_bulk_continuation)
1293ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch			hpriv->caps |= USBFS_CAP_BULK_CONTINUATION;
12945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	}
12955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
12965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	return usbi_add_pollfd(HANDLE_CTX(handle), hpriv->fd, POLLOUT);
12975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
12985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
12995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static void op_close(struct libusb_device_handle *dev_handle)
13005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){
13015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	int fd = _device_handle_priv(dev_handle)->fd;
13025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	usbi_remove_pollfd(HANDLE_CTX(dev_handle), fd);
13035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	close(fd);
13045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
13055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
13065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int op_get_configuration(struct libusb_device_handle *handle,
13075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	int *config)
13085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){
13095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	int r;
13105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1311ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	if (sysfs_can_relate_devices) {
1312ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		r = sysfs_get_active_config(handle->dev, config);
1313ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	} else {
1314ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		r = usbfs_get_active_config(handle->dev,
1315ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch					    _device_handle_priv(handle)->fd);
1316ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	}
13175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	if (r < 0)
13185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		return r;
13195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1320eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch	if (*config == -1) {
1321eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch		usbi_err(HANDLE_CTX(handle), "device unconfigured");
13225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		*config = 0;
1323eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch	}
13245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
13255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	return 0;
13265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
13275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
13285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int op_set_configuration(struct libusb_device_handle *handle, int config)
13295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){
13305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	struct linux_device_priv *priv = _device_priv(handle->dev);
13315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	int fd = _device_handle_priv(handle)->fd;
13325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	int r = ioctl(fd, IOCTL_USBFS_SETCONFIG, &config);
13335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	if (r) {
13345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		if (errno == EINVAL)
13355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)			return LIBUSB_ERROR_NOT_FOUND;
13365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		else if (errno == EBUSY)
13375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)			return LIBUSB_ERROR_BUSY;
13385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		else if (errno == ENODEV)
13395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)			return LIBUSB_ERROR_NO_DEVICE;
13405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
13415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		usbi_err(HANDLE_CTX(handle), "failed, error %d errno %d", r, errno);
13425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		return LIBUSB_ERROR_OTHER;
13435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	}
13445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1345ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	/* update our cached active config descriptor */
1346ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	priv->active_config = config;
13475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1348ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	return LIBUSB_SUCCESS;
13495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
13505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1351ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdochstatic int claim_interface(struct libusb_device_handle *handle, int iface)
13525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){
13535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	int fd = _device_handle_priv(handle)->fd;
13545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	int r = ioctl(fd, IOCTL_USBFS_CLAIMINTF, &iface);
13555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	if (r) {
13565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		if (errno == ENOENT)
13575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)			return LIBUSB_ERROR_NOT_FOUND;
13585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		else if (errno == EBUSY)
13595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)			return LIBUSB_ERROR_BUSY;
13605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		else if (errno == ENODEV)
13615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)			return LIBUSB_ERROR_NO_DEVICE;
13625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
13635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		usbi_err(HANDLE_CTX(handle),
13645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)			"claim interface failed, error %d errno %d", r, errno);
13655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		return LIBUSB_ERROR_OTHER;
13665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	}
13675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	return 0;
13685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
13695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1370ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdochstatic int release_interface(struct libusb_device_handle *handle, int iface)
13715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){
13725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	int fd = _device_handle_priv(handle)->fd;
13735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	int r = ioctl(fd, IOCTL_USBFS_RELEASEINTF, &iface);
13745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	if (r) {
13755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		if (errno == ENODEV)
13765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)			return LIBUSB_ERROR_NO_DEVICE;
13775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
13785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		usbi_err(HANDLE_CTX(handle),
13795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)			"release interface failed, error %d errno %d", r, errno);
13805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		return LIBUSB_ERROR_OTHER;
13815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	}
13825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	return 0;
13835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
13845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
13855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int op_set_interface(struct libusb_device_handle *handle, int iface,
13865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	int altsetting)
13875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){
13885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	int fd = _device_handle_priv(handle)->fd;
13895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	struct usbfs_setinterface setintf;
13905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	int r;
13915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
13925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	setintf.interface = iface;
13935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	setintf.altsetting = altsetting;
13945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	r = ioctl(fd, IOCTL_USBFS_SETINTF, &setintf);
13955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	if (r) {
13965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		if (errno == EINVAL)
13975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)			return LIBUSB_ERROR_NOT_FOUND;
13985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		else if (errno == ENODEV)
13995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)			return LIBUSB_ERROR_NO_DEVICE;
14005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
14015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		usbi_err(HANDLE_CTX(handle),
14025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)			"setintf failed error %d errno %d", r, errno);
14035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		return LIBUSB_ERROR_OTHER;
14045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	}
14055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
14065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	return 0;
14075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
14085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
14095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int op_clear_halt(struct libusb_device_handle *handle,
14105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	unsigned char endpoint)
14115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){
14125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	int fd = _device_handle_priv(handle)->fd;
14135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	unsigned int _endpoint = endpoint;
14145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	int r = ioctl(fd, IOCTL_USBFS_CLEAR_HALT, &_endpoint);
14155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	if (r) {
14165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		if (errno == ENOENT)
14175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)			return LIBUSB_ERROR_NOT_FOUND;
14185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		else if (errno == ENODEV)
14195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)			return LIBUSB_ERROR_NO_DEVICE;
14205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
14215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		usbi_err(HANDLE_CTX(handle),
14225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)			"clear_halt failed error %d errno %d", r, errno);
14235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		return LIBUSB_ERROR_OTHER;
14245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	}
14255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
14265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	return 0;
14275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
14285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
14295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int op_reset_device(struct libusb_device_handle *handle)
14305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){
14315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	int fd = _device_handle_priv(handle)->fd;
14325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	int i, r, ret = 0;
14335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
14345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	/* Doing a device reset will cause the usbfs driver to get unbound
14355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	   from any interfaces it is bound to. By voluntarily unbinding
14365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	   the usbfs driver ourself, we stop the kernel from rebinding
14375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	   the interface after reset (which would end up with the interface
14385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	   getting bound to the in kernel driver if any). */
14395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	for (i = 0; i < USB_MAXINTERFACES; i++) {
14405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		if (handle->claimed_interfaces & (1L << i)) {
1441ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch			release_interface(handle, i);
14425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		}
14435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	}
14445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
14455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	usbi_mutex_lock(&handle->lock);
14465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	r = ioctl(fd, IOCTL_USBFS_RESET, NULL);
14475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	if (r) {
14485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		if (errno == ENODEV) {
14495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)			ret = LIBUSB_ERROR_NOT_FOUND;
14505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)			goto out;
14515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		}
14525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
14535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		usbi_err(HANDLE_CTX(handle),
14545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)			"reset failed error %d errno %d", r, errno);
14555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		ret = LIBUSB_ERROR_OTHER;
14565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		goto out;
14575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	}
14585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
14595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	/* And re-claim any interfaces which were claimed before the reset */
14605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	for (i = 0; i < USB_MAXINTERFACES; i++) {
14615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		if (handle->claimed_interfaces & (1L << i)) {
1462ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch			/*
1463ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch			 * A driver may have completed modprobing during
1464ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch			 * IOCTL_USBFS_RESET, and bound itself as soon as
1465ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch			 * IOCTL_USBFS_RESET released the device lock
1466ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch			 */
1467ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch			r = detach_kernel_driver_and_claim(handle, i);
14685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)			if (r) {
14695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)				usbi_warn(HANDLE_CTX(handle),
1470ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch					"failed to re-claim interface %d after reset: %s",
1471ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch					i, libusb_error_name(r));
14725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)				handle->claimed_interfaces &= ~(1L << i);
1473ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch				ret = LIBUSB_ERROR_NOT_FOUND;
14745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)			}
14755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		}
14765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	}
14775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)out:
14785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	usbi_mutex_unlock(&handle->lock);
14795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	return ret;
14805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
14815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
14825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int op_kernel_driver_active(struct libusb_device_handle *handle,
14835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	int interface)
14845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){
14855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	int fd = _device_handle_priv(handle)->fd;
14865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	struct usbfs_getdriver getdrv;
14875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	int r;
14885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
14895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	getdrv.interface = interface;
14905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	r = ioctl(fd, IOCTL_USBFS_GETDRIVER, &getdrv);
14915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	if (r) {
14925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		if (errno == ENODATA)
14935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)			return 0;
14945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		else if (errno == ENODEV)
14955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)			return LIBUSB_ERROR_NO_DEVICE;
14965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
14975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		usbi_err(HANDLE_CTX(handle),
14985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)			"get driver failed error %d errno %d", r, errno);
14995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		return LIBUSB_ERROR_OTHER;
15005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	}
15015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1502ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	return (strcmp(getdrv.driver, "usbfs") == 0) ? 0 : 1;
15035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
15045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
15055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int op_detach_kernel_driver(struct libusb_device_handle *handle,
15065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	int interface)
15075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){
15085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	int fd = _device_handle_priv(handle)->fd;
15095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	struct usbfs_ioctl command;
1510ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	struct usbfs_getdriver getdrv;
15115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	int r;
15125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
15135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	command.ifno = interface;
15145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	command.ioctl_code = IOCTL_USBFS_DISCONNECT;
15155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	command.data = NULL;
15165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1517ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	getdrv.interface = interface;
1518ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	r = ioctl(fd, IOCTL_USBFS_GETDRIVER, &getdrv);
1519ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	if (r == 0 && strcmp(getdrv.driver, "usbfs") == 0)
1520ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		return LIBUSB_ERROR_NOT_FOUND;
1521ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
15225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	r = ioctl(fd, IOCTL_USBFS_IOCTL, &command);
15235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	if (r) {
15245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		if (errno == ENODATA)
15255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)			return LIBUSB_ERROR_NOT_FOUND;
15265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		else if (errno == EINVAL)
15275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)			return LIBUSB_ERROR_INVALID_PARAM;
15285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		else if (errno == ENODEV)
15295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)			return LIBUSB_ERROR_NO_DEVICE;
15305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
15315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		usbi_err(HANDLE_CTX(handle),
15325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)			"detach failed error %d errno %d", r, errno);
15335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		return LIBUSB_ERROR_OTHER;
15345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	}
15355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
15365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	return 0;
15375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
15385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
15395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int op_attach_kernel_driver(struct libusb_device_handle *handle,
15405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	int interface)
15415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){
15425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	int fd = _device_handle_priv(handle)->fd;
15435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	struct usbfs_ioctl command;
15445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	int r;
15455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
15465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	command.ifno = interface;
15475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	command.ioctl_code = IOCTL_USBFS_CONNECT;
15485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	command.data = NULL;
15495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
15505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	r = ioctl(fd, IOCTL_USBFS_IOCTL, &command);
15515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	if (r < 0) {
15525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		if (errno == ENODATA)
15535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)			return LIBUSB_ERROR_NOT_FOUND;
15545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		else if (errno == EINVAL)
15555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)			return LIBUSB_ERROR_INVALID_PARAM;
15565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		else if (errno == ENODEV)
15575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)			return LIBUSB_ERROR_NO_DEVICE;
15585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		else if (errno == EBUSY)
15595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)			return LIBUSB_ERROR_BUSY;
15605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
15615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		usbi_err(HANDLE_CTX(handle),
15625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)			"attach failed error %d errno %d", r, errno);
15635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		return LIBUSB_ERROR_OTHER;
15645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	} else if (r == 0) {
15655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		return LIBUSB_ERROR_NOT_FOUND;
15665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	}
15675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
15685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	return 0;
15695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
15705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1571ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdochstatic int detach_kernel_driver_and_claim(struct libusb_device_handle *handle,
1572ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	int interface)
1573ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch{
1574ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	struct usbfs_disconnect_claim dc;
1575ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	int r, fd = _device_handle_priv(handle)->fd;
1576ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
1577ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	dc.interface = interface;
1578ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	strcpy(dc.driver, "usbfs");
1579ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	dc.flags = USBFS_DISCONNECT_CLAIM_EXCEPT_DRIVER;
1580ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	r = ioctl(fd, IOCTL_USBFS_DISCONNECT_CLAIM, &dc);
1581ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	if (r == 0 || (r != 0 && errno != ENOTTY)) {
1582ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		if (r == 0)
1583ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch			return 0;
1584ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
1585ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		switch (errno) {
1586ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		case EBUSY:
1587ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch			return LIBUSB_ERROR_BUSY;
1588ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		case EINVAL:
1589ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch			return LIBUSB_ERROR_INVALID_PARAM;
1590ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		case ENODEV:
1591ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch			return LIBUSB_ERROR_NO_DEVICE;
1592ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		}
1593ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		usbi_err(HANDLE_CTX(handle),
1594ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch			"disconnect-and-claim failed errno %d", errno);
1595ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		return LIBUSB_ERROR_OTHER;
1596ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	}
1597ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
1598ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	/* Fallback code for kernels which don't support the
1599ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	   disconnect-and-claim ioctl */
1600ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	r = op_detach_kernel_driver(handle, interface);
1601ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	if (r != 0 && r != LIBUSB_ERROR_NOT_FOUND)
1602ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		return r;
1603ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
1604ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	return claim_interface(handle, interface);
1605ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch}
1606ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
1607ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdochstatic int op_claim_interface(struct libusb_device_handle *handle, int iface)
1608ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch{
1609ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	if (handle->auto_detach_kernel_driver)
1610ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		return detach_kernel_driver_and_claim(handle, iface);
1611ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	else
1612ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		return claim_interface(handle, iface);
1613ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch}
1614ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
1615ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdochstatic int op_release_interface(struct libusb_device_handle *handle, int iface)
1616ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch{
1617ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	int r;
1618ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
1619ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	r = release_interface(handle, iface);
1620ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	if (r)
1621ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		return r;
1622ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
1623ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	if (handle->auto_detach_kernel_driver)
1624ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		op_attach_kernel_driver(handle, iface);
1625ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
1626ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	return 0;
1627ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch}
1628ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
16295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static void op_destroy_device(struct libusb_device *dev)
16305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){
16315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	struct linux_device_priv *priv = _device_priv(dev);
1632ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	if (priv->descriptors)
1633ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		free(priv->descriptors);
16345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	if (priv->sysfs_dir)
16355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		free(priv->sysfs_dir);
16365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
16375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
16385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/* URBs are discarded in reverse order of submission to avoid races. */
16395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int discard_urbs(struct usbi_transfer *itransfer, int first, int last_plus_one)
16405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){
16415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	struct libusb_transfer *transfer =
16425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
16435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	struct linux_transfer_priv *tpriv =
16445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		usbi_transfer_get_os_priv(itransfer);
16455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	struct linux_device_handle_priv *dpriv =
16465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		_device_handle_priv(transfer->dev_handle);
16475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	int i, ret = 0;
16485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	struct usbfs_urb *urb;
16495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
16505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	for (i = last_plus_one - 1; i >= first; i--) {
16515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		if (LIBUSB_TRANSFER_TYPE_ISOCHRONOUS == transfer->type)
16525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)			urb = tpriv->iso_urbs[i];
16535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		else
16545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)			urb = &tpriv->urbs[i];
16555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
16565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		if (0 == ioctl(dpriv->fd, IOCTL_USBFS_DISCARDURB, urb))
16575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)			continue;
16585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
16595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		if (EINVAL == errno) {
16605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)			usbi_dbg("URB not found --> assuming ready to be reaped");
1661eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch			if (i == (last_plus_one - 1))
1662eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch				ret = LIBUSB_ERROR_NOT_FOUND;
16635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		} else if (ENODEV == errno) {
16645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)			usbi_dbg("Device not found for URB --> assuming ready to be reaped");
16655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)			ret = LIBUSB_ERROR_NO_DEVICE;
16665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		} else {
16675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)			usbi_warn(TRANSFER_CTX(transfer),
16685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)				"unrecognised discard errno %d", errno);
16695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)			ret = LIBUSB_ERROR_OTHER;
16705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		}
16715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	}
16725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	return ret;
16735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
16745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
16755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static void free_iso_urbs(struct linux_transfer_priv *tpriv)
16765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){
16775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	int i;
16785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	for (i = 0; i < tpriv->num_urbs; i++) {
16795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		struct usbfs_urb *urb = tpriv->iso_urbs[i];
16805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		if (!urb)
16815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)			break;
16825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		free(urb);
16835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	}
16845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
16855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	free(tpriv->iso_urbs);
16865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	tpriv->iso_urbs = NULL;
16875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
16885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
16895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int submit_bulk_transfer(struct usbi_transfer *itransfer,
16905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	unsigned char urb_type)
16915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){
16925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	struct libusb_transfer *transfer =
16935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
16945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	struct linux_transfer_priv *tpriv = usbi_transfer_get_os_priv(itransfer);
16955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	struct linux_device_handle_priv *dpriv =
16965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		_device_handle_priv(transfer->dev_handle);
16975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	struct usbfs_urb *urbs;
16985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	int is_out = (transfer->endpoint & LIBUSB_ENDPOINT_DIR_MASK)
16995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		== LIBUSB_ENDPOINT_OUT;
1700ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	int bulk_buffer_len, use_bulk_continuation;
17015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	int r;
17025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	int i;
17035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	size_t alloc_size;
17045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
17055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	if (tpriv->urbs)
17065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		return LIBUSB_ERROR_BUSY;
17075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1708ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	if (is_out && (transfer->flags & LIBUSB_TRANSFER_ADD_ZERO_PACKET) &&
1709ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch			!(dpriv->caps & USBFS_CAP_ZERO_PACKET))
1710eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch		return LIBUSB_ERROR_NOT_SUPPORTED;
1711eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
1712ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	/*
1713ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	 * Older versions of usbfs place a 16kb limit on bulk URBs. We work
1714ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	 * around this by splitting large transfers into 16k blocks, and then
1715ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	 * submit all urbs at once. it would be simpler to submit one urb at
1716ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	 * a time, but there is a big performance gain doing it this way.
1717ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	 *
1718ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	 * Newer versions lift the 16k limit (USBFS_CAP_NO_PACKET_SIZE_LIM),
1719ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	 * using arbritary large transfers can still be a bad idea though, as
1720ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	 * the kernel needs to allocate physical contiguous memory for this,
1721ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	 * which may fail for large buffers.
1722ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	 *
1723ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	 * The kernel solves this problem by splitting the transfer into
1724ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	 * blocks itself when the host-controller is scatter-gather capable
1725ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	 * (USBFS_CAP_BULK_SCATTER_GATHER), which most controllers are.
1726ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	 *
1727ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	 * Last, there is the issue of short-transfers when splitting, for
1728ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	 * short split-transfers to work reliable USBFS_CAP_BULK_CONTINUATION
1729ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	 * is needed, but this is not always available.
1730ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	 */
1731ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	if (dpriv->caps & USBFS_CAP_BULK_SCATTER_GATHER) {
1732ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		/* Good! Just submit everything in one go */
1733ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		bulk_buffer_len = transfer->length ? transfer->length : 1;
1734ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		use_bulk_continuation = 0;
1735ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	} else if (dpriv->caps & USBFS_CAP_BULK_CONTINUATION) {
1736ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		/* Split the transfers and use bulk-continuation to
1737ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		   avoid issues with short-transfers */
1738ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		bulk_buffer_len = MAX_BULK_BUFFER_LENGTH;
1739ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		use_bulk_continuation = 1;
1740ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	} else if (dpriv->caps & USBFS_CAP_NO_PACKET_SIZE_LIM) {
1741ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		/* Don't split, assume the kernel can alloc the buffer
1742ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		   (otherwise the submit will fail with -ENOMEM) */
1743ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		bulk_buffer_len = transfer->length ? transfer->length : 1;
1744ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		use_bulk_continuation = 0;
1745ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	} else {
1746ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		/* Bad, splitting without bulk-continuation, short transfers
1747ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		   which end before the last urb will not work reliable! */
1748ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		/* Note we don't warn here as this is "normal" on kernels <
1749ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		   2.6.32 and not a problem for most applications */
1750ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		bulk_buffer_len = MAX_BULK_BUFFER_LENGTH;
1751ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		use_bulk_continuation = 0;
1752ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	}
1753ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
1754ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	int num_urbs = transfer->length / bulk_buffer_len;
17555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	int last_urb_partial = 0;
17565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
17575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	if (transfer->length == 0) {
17585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		num_urbs = 1;
1759ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	} else if ((transfer->length % bulk_buffer_len) > 0) {
17605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		last_urb_partial = 1;
17615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		num_urbs++;
17625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	}
17635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	usbi_dbg("need %d urbs for new transfer with length %d", num_urbs,
17645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		transfer->length);
17655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	alloc_size = num_urbs * sizeof(struct usbfs_urb);
1766ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	urbs = calloc(1, alloc_size);
17675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	if (!urbs)
17685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		return LIBUSB_ERROR_NO_MEM;
17695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	tpriv->urbs = urbs;
17705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	tpriv->num_urbs = num_urbs;
17715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	tpriv->num_retired = 0;
17725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	tpriv->reap_action = NORMAL;
17735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	tpriv->reap_status = LIBUSB_TRANSFER_COMPLETED;
17745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
17755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	for (i = 0; i < num_urbs; i++) {
17765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		struct usbfs_urb *urb = &urbs[i];
17775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		urb->usercontext = itransfer;
17785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		urb->type = urb_type;
17795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		urb->endpoint = transfer->endpoint;
1780ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		urb->buffer = transfer->buffer + (i * bulk_buffer_len);
1781ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		/* don't set the short not ok flag for the last URB */
1782ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		if (use_bulk_continuation && !is_out && (i < num_urbs - 1))
17835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)			urb->flags = USBFS_URB_SHORT_NOT_OK;
17845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		if (i == num_urbs - 1 && last_urb_partial)
1785ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch			urb->buffer_length = transfer->length % bulk_buffer_len;
17865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		else if (transfer->length == 0)
17875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)			urb->buffer_length = 0;
17885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		else
1789ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch			urb->buffer_length = bulk_buffer_len;
17905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1791ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		if (i > 0 && use_bulk_continuation)
17925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)			urb->flags |= USBFS_URB_BULK_CONTINUATION;
17935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1794eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch		/* we have already checked that the flag is supported */
1795eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch		if (is_out && i == num_urbs - 1 &&
1796eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch		    transfer->flags & LIBUSB_TRANSFER_ADD_ZERO_PACKET)
1797eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch			urb->flags |= USBFS_URB_ZERO_PACKET;
1798eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
17995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		r = ioctl(dpriv->fd, IOCTL_USBFS_SUBMITURB, urb);
18005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		if (r < 0) {
18015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)			if (errno == ENODEV) {
18025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)				r = LIBUSB_ERROR_NO_DEVICE;
18035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)			} else {
18045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)				usbi_err(TRANSFER_CTX(transfer),
18055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)					"submiturb failed error %d errno=%d", r, errno);
18065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)				r = LIBUSB_ERROR_IO;
18075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)			}
18085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
18095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)			/* if the first URB submission fails, we can simply free up and
18105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)			 * return failure immediately. */
18115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)			if (i == 0) {
18125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)				usbi_dbg("first URB failed, easy peasy");
18135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)				free(urbs);
18145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)				tpriv->urbs = NULL;
18155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)				return r;
18165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)			}
18175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
18185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)			/* if it's not the first URB that failed, the situation is a bit
18195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)			 * tricky. we may need to discard all previous URBs. there are
18205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)			 * complications:
18215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)			 *  - discarding is asynchronous - discarded urbs will be reaped
18225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)			 *    later. the user must not have freed the transfer when the
1823ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch			 *    discarded URBs are reaped, otherwise libusbx will be using
18245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)			 *    freed memory.
18255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)			 *  - the earlier URBs may have completed successfully and we do
18265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)			 *    not want to throw away any data.
18275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)			 *  - this URB failing may be no error; EREMOTEIO means that
18285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)			 *    this transfer simply didn't need all the URBs we submitted
18295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)			 * so, we report that the transfer was submitted successfully and
18305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)			 * in case of error we discard all previous URBs. later when
18315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)			 * the final reap completes we can report error to the user,
18325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)			 * or success if an earlier URB was completed successfully.
18335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)			 */
18345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)			tpriv->reap_action = EREMOTEIO == errno ? COMPLETED_EARLY : SUBMIT_FAILED;
18355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
18365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)			/* The URBs we haven't submitted yet we count as already
18375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)			 * retired. */
18385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)			tpriv->num_retired += num_urbs - i;
18395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
18405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)			/* If we completed short then don't try to discard. */
18415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)			if (COMPLETED_EARLY == tpriv->reap_action)
18425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)				return 0;
18435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
18445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)			discard_urbs(itransfer, 0, i);
18455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
18465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)			usbi_dbg("reporting successful submission but waiting for %d "
18475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)				"discards before reporting error", i);
18485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)			return 0;
18495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		}
18505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	}
18515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
18525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	return 0;
18535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
18545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
18555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int submit_iso_transfer(struct usbi_transfer *itransfer)
18565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){
18575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	struct libusb_transfer *transfer =
18585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
18595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	struct linux_transfer_priv *tpriv = usbi_transfer_get_os_priv(itransfer);
18605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	struct linux_device_handle_priv *dpriv =
18615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		_device_handle_priv(transfer->dev_handle);
18625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	struct usbfs_urb **urbs;
18635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	size_t alloc_size;
18645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	int num_packets = transfer->num_iso_packets;
18655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	int i;
18665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	int this_urb_len = 0;
18675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	int num_urbs = 1;
18685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	int packet_offset = 0;
18695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	unsigned int packet_len;
18705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	unsigned char *urb_buffer = transfer->buffer;
18715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
18725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	if (tpriv->iso_urbs)
18735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		return LIBUSB_ERROR_BUSY;
18745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
18755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	/* usbfs places a 32kb limit on iso URBs. we divide up larger requests
18765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	 * into smaller units to meet such restriction, then fire off all the
18775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	 * units at once. it would be simpler if we just fired one unit at a time,
1878ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	 * but there is a big performance gain through doing it this way.
1879ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	 *
1880ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	 * Newer kernels lift the 32k limit (USBFS_CAP_NO_PACKET_SIZE_LIM),
1881ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	 * using arbritary large transfers is still be a bad idea though, as
1882ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	 * the kernel needs to allocate physical contiguous memory for this,
1883ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	 * which may fail for large buffers.
1884ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	 */
18855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
18865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	/* calculate how many URBs we need */
18875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	for (i = 0; i < num_packets; i++) {
1888ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		unsigned int space_remaining = MAX_ISO_BUFFER_LENGTH - this_urb_len;
18895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		packet_len = transfer->iso_packet_desc[i].length;
18905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
18915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		if (packet_len > space_remaining) {
18925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)			num_urbs++;
18935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)			this_urb_len = packet_len;
18945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		} else {
18955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)			this_urb_len += packet_len;
18965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		}
18975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	}
18985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	usbi_dbg("need %d 32k URBs for transfer", num_urbs);
18995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
19005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	alloc_size = num_urbs * sizeof(*urbs);
1901ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	urbs = calloc(1, alloc_size);
19025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	if (!urbs)
19035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		return LIBUSB_ERROR_NO_MEM;
19045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
19055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	tpriv->iso_urbs = urbs;
19065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	tpriv->num_urbs = num_urbs;
19075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	tpriv->num_retired = 0;
19085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	tpriv->reap_action = NORMAL;
19095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	tpriv->iso_packet_offset = 0;
19105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
19115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	/* allocate + initialize each URB with the correct number of packets */
19125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	for (i = 0; i < num_urbs; i++) {
19135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		struct usbfs_urb *urb;
1914ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		unsigned int space_remaining_in_urb = MAX_ISO_BUFFER_LENGTH;
19155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		int urb_packet_offset = 0;
19165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		unsigned char *urb_buffer_orig = urb_buffer;
19175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		int j;
19185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		int k;
19195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
19205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		/* swallow up all the packets we can fit into this URB */
19215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		while (packet_offset < transfer->num_iso_packets) {
19225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)			packet_len = transfer->iso_packet_desc[packet_offset].length;
19235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)			if (packet_len <= space_remaining_in_urb) {
19245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)				/* throw it in */
19255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)				urb_packet_offset++;
19265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)				packet_offset++;
19275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)				space_remaining_in_urb -= packet_len;
19285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)				urb_buffer += packet_len;
19295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)			} else {
19305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)				/* it can't fit, save it for the next URB */
19315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)				break;
19325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)			}
19335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		}
19345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
19355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		alloc_size = sizeof(*urb)
19365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)			+ (urb_packet_offset * sizeof(struct usbfs_iso_packet_desc));
1937ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		urb = calloc(1, alloc_size);
19385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		if (!urb) {
19395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)			free_iso_urbs(tpriv);
19405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)			return LIBUSB_ERROR_NO_MEM;
19415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		}
19425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		urbs[i] = urb;
19435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
19445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		/* populate packet lengths */
19455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		for (j = 0, k = packet_offset - urb_packet_offset;
19465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)				k < packet_offset; k++, j++) {
19475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)			packet_len = transfer->iso_packet_desc[k].length;
19485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)			urb->iso_frame_desc[j].length = packet_len;
19495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		}
19505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
19515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		urb->usercontext = itransfer;
19525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		urb->type = USBFS_URB_TYPE_ISO;
19535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		/* FIXME: interface for non-ASAP data? */
19545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		urb->flags = USBFS_URB_ISO_ASAP;
19555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		urb->endpoint = transfer->endpoint;
19565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		urb->number_of_packets = urb_packet_offset;
19575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		urb->buffer = urb_buffer_orig;
19585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	}
19595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
19605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	/* submit URBs */
19615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	for (i = 0; i < num_urbs; i++) {
19625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		int r = ioctl(dpriv->fd, IOCTL_USBFS_SUBMITURB, urbs[i]);
19635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		if (r < 0) {
19645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)			if (errno == ENODEV) {
19655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)				r = LIBUSB_ERROR_NO_DEVICE;
19665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)			} else {
19675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)				usbi_err(TRANSFER_CTX(transfer),
19685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)					"submiturb failed error %d errno=%d", r, errno);
19695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)				r = LIBUSB_ERROR_IO;
19705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)			}
19715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
19725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)			/* if the first URB submission fails, we can simply free up and
19735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)			 * return failure immediately. */
19745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)			if (i == 0) {
19755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)				usbi_dbg("first URB failed, easy peasy");
19765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)				free_iso_urbs(tpriv);
19775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)				return r;
19785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)			}
19795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
19805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)			/* if it's not the first URB that failed, the situation is a bit
19815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)			 * tricky. we must discard all previous URBs. there are
19825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)			 * complications:
19835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)			 *  - discarding is asynchronous - discarded urbs will be reaped
19845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)			 *    later. the user must not have freed the transfer when the
1985ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch			 *    discarded URBs are reaped, otherwise libusbx will be using
19865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)			 *    freed memory.
19875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)			 *  - the earlier URBs may have completed successfully and we do
19885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)			 *    not want to throw away any data.
19895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)			 * so, in this case we discard all the previous URBs BUT we report
19905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)			 * that the transfer was submitted successfully. then later when
19915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)			 * the final discard completes we can report error to the user.
19925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)			 */
19935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)			tpriv->reap_action = SUBMIT_FAILED;
19945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
19955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)			/* The URBs we haven't submitted yet we count as already
19965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)			 * retired. */
19975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)			tpriv->num_retired = num_urbs - i;
19985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)			discard_urbs(itransfer, 0, i);
19995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
20005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)			usbi_dbg("reporting successful submission but waiting for %d "
20015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)				"discards before reporting error", i);
20025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)			return 0;
20035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		}
20045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	}
20055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
20065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	return 0;
20075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
20085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
20095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int submit_control_transfer(struct usbi_transfer *itransfer)
20105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){
20115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	struct linux_transfer_priv *tpriv = usbi_transfer_get_os_priv(itransfer);
20125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	struct libusb_transfer *transfer =
20135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
20145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	struct linux_device_handle_priv *dpriv =
20155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		_device_handle_priv(transfer->dev_handle);
20165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	struct usbfs_urb *urb;
20175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	int r;
20185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
20195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	if (tpriv->urbs)
20205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		return LIBUSB_ERROR_BUSY;
20215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
20225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	if (transfer->length - LIBUSB_CONTROL_SETUP_SIZE > MAX_CTRL_BUFFER_LENGTH)
20235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		return LIBUSB_ERROR_INVALID_PARAM;
20245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2025ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	urb = calloc(1, sizeof(struct usbfs_urb));
20265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	if (!urb)
20275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		return LIBUSB_ERROR_NO_MEM;
20285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	tpriv->urbs = urb;
20295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	tpriv->num_urbs = 1;
20305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	tpriv->reap_action = NORMAL;
20315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
20325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	urb->usercontext = itransfer;
20335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	urb->type = USBFS_URB_TYPE_CONTROL;
20345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	urb->endpoint = transfer->endpoint;
20355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	urb->buffer = transfer->buffer;
20365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	urb->buffer_length = transfer->length;
20375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
20385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	r = ioctl(dpriv->fd, IOCTL_USBFS_SUBMITURB, urb);
20395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	if (r < 0) {
20405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		free(urb);
20415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		tpriv->urbs = NULL;
20425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		if (errno == ENODEV)
20435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)			return LIBUSB_ERROR_NO_DEVICE;
20445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
20455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		usbi_err(TRANSFER_CTX(transfer),
20465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)			"submiturb failed error %d errno=%d", r, errno);
20475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		return LIBUSB_ERROR_IO;
20485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	}
20495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	return 0;
20505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
20515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
20525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int op_submit_transfer(struct usbi_transfer *itransfer)
20535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){
20545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	struct libusb_transfer *transfer =
20555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
20565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
20575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	switch (transfer->type) {
20585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	case LIBUSB_TRANSFER_TYPE_CONTROL:
20595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		return submit_control_transfer(itransfer);
20605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	case LIBUSB_TRANSFER_TYPE_BULK:
20615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		return submit_bulk_transfer(itransfer, USBFS_URB_TYPE_BULK);
20625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	case LIBUSB_TRANSFER_TYPE_INTERRUPT:
20635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		return submit_bulk_transfer(itransfer, USBFS_URB_TYPE_INTERRUPT);
20645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	case LIBUSB_TRANSFER_TYPE_ISOCHRONOUS:
20655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		return submit_iso_transfer(itransfer);
20665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	default:
20675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		usbi_err(TRANSFER_CTX(transfer),
20685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)			"unknown endpoint type %d", transfer->type);
20695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		return LIBUSB_ERROR_INVALID_PARAM;
20705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	}
20715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
20725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
20735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int op_cancel_transfer(struct usbi_transfer *itransfer)
20745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){
20755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	struct linux_transfer_priv *tpriv = usbi_transfer_get_os_priv(itransfer);
20765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	struct libusb_transfer *transfer =
20775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
20785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
20795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	switch (transfer->type) {
20805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	case LIBUSB_TRANSFER_TYPE_BULK:
20815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		if (tpriv->reap_action == ERROR)
20825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)			break;
20835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		/* else, fall through */
20845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	case LIBUSB_TRANSFER_TYPE_CONTROL:
20855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	case LIBUSB_TRANSFER_TYPE_INTERRUPT:
20865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	case LIBUSB_TRANSFER_TYPE_ISOCHRONOUS:
20875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		tpriv->reap_action = CANCELLED;
20885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		break;
20895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	default:
20905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		usbi_err(TRANSFER_CTX(transfer),
20915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)			"unknown endpoint type %d", transfer->type);
20925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		return LIBUSB_ERROR_INVALID_PARAM;
20935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	}
20945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
20955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	if (!tpriv->urbs)
20965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		return LIBUSB_ERROR_NOT_FOUND;
20975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
20985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	return discard_urbs(itransfer, 0, tpriv->num_urbs);
20995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
21005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
21015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static void op_clear_transfer_priv(struct usbi_transfer *itransfer)
21025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){
21035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	struct libusb_transfer *transfer =
21045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
21055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	struct linux_transfer_priv *tpriv = usbi_transfer_get_os_priv(itransfer);
21065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
21075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	/* urbs can be freed also in submit_transfer so lock mutex first */
21085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	switch (transfer->type) {
21095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	case LIBUSB_TRANSFER_TYPE_CONTROL:
21105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	case LIBUSB_TRANSFER_TYPE_BULK:
21115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	case LIBUSB_TRANSFER_TYPE_INTERRUPT:
21125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		usbi_mutex_lock(&itransfer->lock);
21135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		if (tpriv->urbs)
21145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)			free(tpriv->urbs);
21155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		tpriv->urbs = NULL;
21165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		usbi_mutex_unlock(&itransfer->lock);
21175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		break;
21185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	case LIBUSB_TRANSFER_TYPE_ISOCHRONOUS:
21195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		usbi_mutex_lock(&itransfer->lock);
21205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		if (tpriv->iso_urbs)
21215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)			free_iso_urbs(tpriv);
21225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		usbi_mutex_unlock(&itransfer->lock);
21235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		break;
21245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	default:
21255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		usbi_err(TRANSFER_CTX(transfer),
21265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)			"unknown endpoint type %d", transfer->type);
21275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	}
21285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
21295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
21305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int handle_bulk_completion(struct usbi_transfer *itransfer,
21315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	struct usbfs_urb *urb)
21325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){
21335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	struct linux_transfer_priv *tpriv = usbi_transfer_get_os_priv(itransfer);
21345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
21355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	int urb_idx = urb - tpriv->urbs;
21365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
21375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	usbi_mutex_lock(&itransfer->lock);
21385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	usbi_dbg("handling completion status %d of bulk urb %d/%d", urb->status,
21395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		urb_idx + 1, tpriv->num_urbs);
21405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
21415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	tpriv->num_retired++;
21425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
21435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	if (tpriv->reap_action != NORMAL) {
21445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		/* cancelled, submit_fail, or completed early */
21455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		usbi_dbg("abnormal reap: urb status %d", urb->status);
21465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
21475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		/* even though we're in the process of cancelling, it's possible that
21485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		 * we may receive some data in these URBs that we don't want to lose.
21495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		 * examples:
21505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		 * 1. while the kernel is cancelling all the packets that make up an
21515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		 *    URB, a few of them might complete. so we get back a successful
21525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		 *    cancellation *and* some data.
21535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		 * 2. we receive a short URB which marks the early completion condition,
21545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		 *    so we start cancelling the remaining URBs. however, we're too
21555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		 *    slow and another URB completes (or at least completes partially).
21565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		 *    (this can't happen since we always use BULK_CONTINUATION.)
21575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		 *
21585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		 * When this happens, our objectives are not to lose any "surplus" data,
21595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		 * and also to stick it at the end of the previously-received data
2160ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		 * (closing any holes), so that libusbx reports the total amount of
21615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		 * transferred data and presents it in a contiguous chunk.
21625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		 */
21635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		if (urb->actual_length > 0) {
21645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)			unsigned char *target = transfer->buffer + itransfer->transferred;
21655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)			usbi_dbg("received %d bytes of surplus data", urb->actual_length);
21665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)			if (urb->buffer != target) {
21675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)				usbi_dbg("moving surplus data from offset %d to offset %d",
21685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)					(unsigned char *) urb->buffer - transfer->buffer,
21695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)					target - transfer->buffer);
21705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)				memmove(target, urb->buffer, urb->actual_length);
21715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)			}
21725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)			itransfer->transferred += urb->actual_length;
21735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		}
21745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
21755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		if (tpriv->num_retired == tpriv->num_urbs) {
21765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)			usbi_dbg("abnormal reap: last URB handled, reporting");
21775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)			if (tpriv->reap_action != COMPLETED_EARLY &&
21785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)			    tpriv->reap_status == LIBUSB_TRANSFER_COMPLETED)
21795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)				tpriv->reap_status = LIBUSB_TRANSFER_ERROR;
21805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)			goto completed;
21815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		}
21825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		goto out_unlock;
21835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	}
21845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
21855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	itransfer->transferred += urb->actual_length;
21865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
21875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	/* Many of these errors can occur on *any* urb of a multi-urb
21885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	 * transfer.  When they do, we tear down the rest of the transfer.
21895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	 */
21905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	switch (urb->status) {
21915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	case 0:
21925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		break;
21935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	case -EREMOTEIO: /* short transfer */
21945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		break;
21955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	case -ENOENT: /* cancelled */
21965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	case -ECONNRESET:
21975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		break;
2198eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch	case -ENODEV:
21995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	case -ESHUTDOWN:
22005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		usbi_dbg("device removed");
22015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		tpriv->reap_status = LIBUSB_TRANSFER_NO_DEVICE;
22025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		goto cancel_remaining;
22035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	case -EPIPE:
22045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		usbi_dbg("detected endpoint stall");
22055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		if (tpriv->reap_status == LIBUSB_TRANSFER_COMPLETED)
22065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)			tpriv->reap_status = LIBUSB_TRANSFER_STALL;
22075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		goto cancel_remaining;
22085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	case -EOVERFLOW:
22095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		/* overflow can only ever occur in the last urb */
22105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		usbi_dbg("overflow, actual_length=%d", urb->actual_length);
22115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		if (tpriv->reap_status == LIBUSB_TRANSFER_COMPLETED)
22125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)			tpriv->reap_status = LIBUSB_TRANSFER_OVERFLOW;
22135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		goto completed;
22145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	case -ETIME:
22155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	case -EPROTO:
22165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	case -EILSEQ:
2217eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch	case -ECOMM:
2218eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch	case -ENOSR:
22195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		usbi_dbg("low level error %d", urb->status);
22205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		tpriv->reap_action = ERROR;
22215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		goto cancel_remaining;
22225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	default:
22235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		usbi_warn(ITRANSFER_CTX(itransfer),
22245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)			"unrecognised urb status %d", urb->status);
22255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		tpriv->reap_action = ERROR;
22265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		goto cancel_remaining;
22275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	}
22285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
22295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	/* if we're the last urb or we got less data than requested then we're
22305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	 * done */
22315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	if (urb_idx == tpriv->num_urbs - 1) {
22325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		usbi_dbg("last URB in transfer --> complete!");
22335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		goto completed;
22345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	} else if (urb->actual_length < urb->buffer_length) {
22355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		usbi_dbg("short transfer %d/%d --> complete!",
22365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)			urb->actual_length, urb->buffer_length);
22375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		if (tpriv->reap_action == NORMAL)
22385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)			tpriv->reap_action = COMPLETED_EARLY;
22395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	} else
22405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		goto out_unlock;
22415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
22425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)cancel_remaining:
22435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	if (ERROR == tpriv->reap_action && LIBUSB_TRANSFER_COMPLETED == tpriv->reap_status)
22445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		tpriv->reap_status = LIBUSB_TRANSFER_ERROR;
22455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
22465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	if (tpriv->num_retired == tpriv->num_urbs) /* nothing to cancel */
22475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		goto completed;
22485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
22495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	/* cancel remaining urbs and wait for their completion before
22505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	 * reporting results */
22515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	discard_urbs(itransfer, urb_idx + 1, tpriv->num_urbs);
22525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
22535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)out_unlock:
22545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	usbi_mutex_unlock(&itransfer->lock);
22555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	return 0;
22565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
22575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)completed:
22585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	free(tpriv->urbs);
22595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	tpriv->urbs = NULL;
22605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	usbi_mutex_unlock(&itransfer->lock);
22615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	return CANCELLED == tpriv->reap_action ?
22625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		usbi_handle_transfer_cancellation(itransfer) :
22635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		usbi_handle_transfer_completion(itransfer, tpriv->reap_status);
22645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
22655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
22665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int handle_iso_completion(struct usbi_transfer *itransfer,
22675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	struct usbfs_urb *urb)
22685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){
22695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	struct libusb_transfer *transfer =
22705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
22715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	struct linux_transfer_priv *tpriv = usbi_transfer_get_os_priv(itransfer);
22725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	int num_urbs = tpriv->num_urbs;
22735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	int urb_idx = 0;
22745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	int i;
22755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	enum libusb_transfer_status status = LIBUSB_TRANSFER_COMPLETED;
22765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
22775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	usbi_mutex_lock(&itransfer->lock);
22785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	for (i = 0; i < num_urbs; i++) {
22795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		if (urb == tpriv->iso_urbs[i]) {
22805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)			urb_idx = i + 1;
22815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)			break;
22825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		}
22835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	}
22845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	if (urb_idx == 0) {
22855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		usbi_err(TRANSFER_CTX(transfer), "could not locate urb!");
22865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		usbi_mutex_unlock(&itransfer->lock);
22875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		return LIBUSB_ERROR_NOT_FOUND;
22885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	}
22895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
22905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	usbi_dbg("handling completion status %d of iso urb %d/%d", urb->status,
22915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		urb_idx, num_urbs);
22925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
22935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	/* copy isochronous results back in */
22945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
22955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	for (i = 0; i < urb->number_of_packets; i++) {
22965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		struct usbfs_iso_packet_desc *urb_desc = &urb->iso_frame_desc[i];
22975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		struct libusb_iso_packet_descriptor *lib_desc =
22985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)			&transfer->iso_packet_desc[tpriv->iso_packet_offset++];
2299eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch		lib_desc->status = LIBUSB_TRANSFER_COMPLETED;
2300eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch		switch (urb_desc->status) {
2301eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch		case 0:
2302eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch			break;
2303eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch		case -ENOENT: /* cancelled */
2304eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch		case -ECONNRESET:
2305eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch			break;
2306eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch		case -ENODEV:
2307eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch		case -ESHUTDOWN:
2308eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch			usbi_dbg("device removed");
2309eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch			lib_desc->status = LIBUSB_TRANSFER_NO_DEVICE;
2310eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch			break;
2311eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch		case -EPIPE:
2312eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch			usbi_dbg("detected endpoint stall");
2313eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch			lib_desc->status = LIBUSB_TRANSFER_STALL;
2314eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch			break;
2315eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch		case -EOVERFLOW:
2316eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch			usbi_dbg("overflow error");
2317eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch			lib_desc->status = LIBUSB_TRANSFER_OVERFLOW;
2318eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch			break;
2319eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch		case -ETIME:
2320eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch		case -EPROTO:
2321eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch		case -EILSEQ:
2322eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch		case -ECOMM:
2323eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch		case -ENOSR:
2324eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch		case -EXDEV:
2325eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch			usbi_dbg("low-level USB error %d", urb_desc->status);
2326eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch			lib_desc->status = LIBUSB_TRANSFER_ERROR;
2327eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch			break;
2328eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch		default:
2329eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch			usbi_warn(TRANSFER_CTX(transfer),
2330eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch				"unrecognised urb status %d", urb_desc->status);
2331eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch			lib_desc->status = LIBUSB_TRANSFER_ERROR;
2332eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch			break;
2333eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch		}
23345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		lib_desc->actual_length = urb_desc->actual_length;
23355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	}
23365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
23375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	tpriv->num_retired++;
23385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
23395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	if (tpriv->reap_action != NORMAL) { /* cancelled or submit_fail */
23405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		usbi_dbg("CANCEL: urb status %d", urb->status);
23415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
23425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		if (tpriv->num_retired == num_urbs) {
23435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)			usbi_dbg("CANCEL: last URB handled, reporting");
23445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)			free_iso_urbs(tpriv);
23455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)			if (tpriv->reap_action == CANCELLED) {
23465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)				usbi_mutex_unlock(&itransfer->lock);
23475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)				return usbi_handle_transfer_cancellation(itransfer);
23485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)			} else {
23495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)				usbi_mutex_unlock(&itransfer->lock);
23505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)				return usbi_handle_transfer_completion(itransfer,
23515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)					LIBUSB_TRANSFER_ERROR);
23525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)			}
23535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		}
23545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		goto out;
23555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	}
23565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
23575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	switch (urb->status) {
23585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	case 0:
23595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		break;
23605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	case -ENOENT: /* cancelled */
2361eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch	case -ECONNRESET:
23625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		break;
23635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	case -ESHUTDOWN:
23645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		usbi_dbg("device removed");
23655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		status = LIBUSB_TRANSFER_NO_DEVICE;
23665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		break;
23675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	default:
23685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		usbi_warn(TRANSFER_CTX(transfer),
23695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)			"unrecognised urb status %d", urb->status);
2370eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch		status = LIBUSB_TRANSFER_ERROR;
23715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		break;
23725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	}
23735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2374eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch	/* if we're the last urb then we're done */
23755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	if (urb_idx == num_urbs) {
23765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		usbi_dbg("last URB in transfer --> complete!");
23775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		free_iso_urbs(tpriv);
23785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		usbi_mutex_unlock(&itransfer->lock);
23795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		return usbi_handle_transfer_completion(itransfer, status);
23805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	}
23815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
23825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)out:
23835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	usbi_mutex_unlock(&itransfer->lock);
23845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	return 0;
23855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
23865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
23875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int handle_control_completion(struct usbi_transfer *itransfer,
23885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	struct usbfs_urb *urb)
23895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){
23905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	struct linux_transfer_priv *tpriv = usbi_transfer_get_os_priv(itransfer);
23915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	int status;
23925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
23935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	usbi_mutex_lock(&itransfer->lock);
23945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	usbi_dbg("handling completion status %d", urb->status);
23955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
23965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	itransfer->transferred += urb->actual_length;
23975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
23985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	if (tpriv->reap_action == CANCELLED) {
23995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		if (urb->status != 0 && urb->status != -ENOENT)
24005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)			usbi_warn(ITRANSFER_CTX(itransfer),
24015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)				"cancel: unrecognised urb status %d", urb->status);
24025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		free(tpriv->urbs);
24035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		tpriv->urbs = NULL;
24045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		usbi_mutex_unlock(&itransfer->lock);
24055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		return usbi_handle_transfer_cancellation(itransfer);
24065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	}
24075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
24085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	switch (urb->status) {
24095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	case 0:
24105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		status = LIBUSB_TRANSFER_COMPLETED;
24115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		break;
24125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	case -ENOENT: /* cancelled */
24135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		status = LIBUSB_TRANSFER_CANCELLED;
24145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		break;
2415eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch	case -ENODEV:
24165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	case -ESHUTDOWN:
24175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		usbi_dbg("device removed");
24185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		status = LIBUSB_TRANSFER_NO_DEVICE;
24195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		break;
24205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	case -EPIPE:
24215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		usbi_dbg("unsupported control request");
24225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		status = LIBUSB_TRANSFER_STALL;
24235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		break;
2424eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch	case -EOVERFLOW:
2425eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch		usbi_dbg("control overflow error");
2426eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch		status = LIBUSB_TRANSFER_OVERFLOW;
2427eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch		break;
24285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	case -ETIME:
24295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	case -EPROTO:
24305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	case -EILSEQ:
2431eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch	case -ECOMM:
2432eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch	case -ENOSR:
24335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		usbi_dbg("low-level bus error occurred");
24345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		status = LIBUSB_TRANSFER_ERROR;
24355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		break;
24365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	default:
24375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		usbi_warn(ITRANSFER_CTX(itransfer),
24385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)			"unrecognised urb status %d", urb->status);
24395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		status = LIBUSB_TRANSFER_ERROR;
24405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		break;
24415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	}
24425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
24435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	free(tpriv->urbs);
24445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	tpriv->urbs = NULL;
24455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	usbi_mutex_unlock(&itransfer->lock);
24465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	return usbi_handle_transfer_completion(itransfer, status);
24475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
24485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
24495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int reap_for_handle(struct libusb_device_handle *handle)
24505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){
24515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	struct linux_device_handle_priv *hpriv = _device_handle_priv(handle);
24525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	int r;
24535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	struct usbfs_urb *urb;
24545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	struct usbi_transfer *itransfer;
24555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	struct libusb_transfer *transfer;
24565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
24575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	r = ioctl(hpriv->fd, IOCTL_USBFS_REAPURBNDELAY, &urb);
24585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	if (r == -1 && errno == EAGAIN)
24595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		return 1;
24605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	if (r < 0) {
24615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		if (errno == ENODEV)
24625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)			return LIBUSB_ERROR_NO_DEVICE;
24635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
24645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		usbi_err(HANDLE_CTX(handle), "reap failed error %d errno=%d",
24655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)			r, errno);
24665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		return LIBUSB_ERROR_IO;
24675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	}
24685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
24695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	itransfer = urb->usercontext;
24705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
24715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
24725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	usbi_dbg("urb type=%d status=%d transferred=%d", urb->type, urb->status,
24735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		urb->actual_length);
24745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
24755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	switch (transfer->type) {
24765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	case LIBUSB_TRANSFER_TYPE_ISOCHRONOUS:
24775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		return handle_iso_completion(itransfer, urb);
24785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	case LIBUSB_TRANSFER_TYPE_BULK:
24795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	case LIBUSB_TRANSFER_TYPE_INTERRUPT:
24805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		return handle_bulk_completion(itransfer, urb);
24815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	case LIBUSB_TRANSFER_TYPE_CONTROL:
24825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		return handle_control_completion(itransfer, urb);
24835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	default:
24845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		usbi_err(HANDLE_CTX(handle), "unrecognised endpoint type %x",
24855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)			transfer->type);
24865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		return LIBUSB_ERROR_OTHER;
24875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	}
24885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
24895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
24905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int op_handle_events(struct libusb_context *ctx,
24915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	struct pollfd *fds, POLL_NFDS_TYPE nfds, int num_ready)
24925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){
24935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	int r;
2494ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	unsigned int i = 0;
24955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
24965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	usbi_mutex_lock(&ctx->open_devs_lock);
24975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	for (i = 0; i < nfds && num_ready > 0; i++) {
24985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		struct pollfd *pollfd = &fds[i];
24995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		struct libusb_device_handle *handle;
25005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		struct linux_device_handle_priv *hpriv = NULL;
25015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
25025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		if (!pollfd->revents)
25035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)			continue;
25045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
25055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		num_ready--;
25065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		list_for_each_entry(handle, &ctx->open_devs, list, struct libusb_device_handle) {
25075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)			hpriv = _device_handle_priv(handle);
25085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)			if (hpriv->fd == pollfd->fd)
25095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)				break;
25105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		}
25115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
25125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		if (pollfd->revents & POLLERR) {
25135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)			usbi_remove_pollfd(HANDLE_CTX(handle), hpriv->fd);
25145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)			usbi_handle_disconnect(handle);
251568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)			/* device will still be marked as attached if hotplug monitor thread
251668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)			 * hasn't processed remove event yet */
251768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)			usbi_mutex_static_lock(&linux_hotplug_lock);
251868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)			if (handle->dev->attached)
251968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)				linux_device_disconnected(handle->dev->bus_number,
252068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)						handle->dev->device_address, NULL);
252168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)			usbi_mutex_static_unlock(&linux_hotplug_lock);
25225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)			continue;
25235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		}
25245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2525ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		do {
2526ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch			r = reap_for_handle(handle);
2527ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch		} while (r == 0);
25285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		if (r == 1 || r == LIBUSB_ERROR_NO_DEVICE)
25295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)			continue;
25305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		else if (r < 0)
25315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)			goto out;
25325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	}
25335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
25345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	r = 0;
25355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)out:
25365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	usbi_mutex_unlock(&ctx->open_devs_lock);
25375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	return r;
25385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
25395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
25405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int op_clock_gettime(int clk_id, struct timespec *tp)
25415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){
25425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	switch (clk_id) {
25435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	case USBI_CLOCK_MONOTONIC:
25445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		return clock_gettime(monotonic_clkid, tp);
25455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	case USBI_CLOCK_REALTIME:
25465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		return clock_gettime(CLOCK_REALTIME, tp);
25475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	default:
25485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		return LIBUSB_ERROR_INVALID_PARAM;
25495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
25505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
25515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
25525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#ifdef USBI_TIMERFD_AVAILABLE
25535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static clockid_t op_get_timerfd_clockid(void)
25545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){
25555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	return monotonic_clkid;
25565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
25575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
25585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
25595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
25605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const struct usbi_os_backend linux_usbfs_backend = {
25615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	.name = "Linux usbfs",
2562ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	.caps = USBI_CAP_HAS_HID_ACCESS|USBI_CAP_SUPPORTS_DETACH_KERNEL_DRIVER,
25635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	.init = op_init,
2564ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	.exit = op_exit,
2565ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	.get_device_list = NULL,
2566ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	.hotplug_poll = op_hotplug_poll,
25675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	.get_device_descriptor = op_get_device_descriptor,
25685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	.get_active_config_descriptor = op_get_active_config_descriptor,
25695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	.get_config_descriptor = op_get_config_descriptor,
2570ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	.get_config_descriptor_by_value = op_get_config_descriptor_by_value,
25715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
25725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	.open = op_open,
25735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	.close = op_close,
25745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	.get_configuration = op_get_configuration,
25755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	.set_configuration = op_set_configuration,
25765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	.claim_interface = op_claim_interface,
25775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	.release_interface = op_release_interface,
25785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
25795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	.set_interface_altsetting = op_set_interface,
25805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	.clear_halt = op_clear_halt,
25815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	.reset_device = op_reset_device,
25825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
25835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	.kernel_driver_active = op_kernel_driver_active,
25845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	.detach_kernel_driver = op_detach_kernel_driver,
25855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	.attach_kernel_driver = op_attach_kernel_driver,
25865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
25875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	.destroy_device = op_destroy_device,
25885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
25895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	.submit_transfer = op_submit_transfer,
25905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	.cancel_transfer = op_cancel_transfer,
25915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	.clear_transfer_priv = op_clear_transfer_priv,
25925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
25935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	.handle_events = op_handle_events,
25945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
25955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	.clock_gettime = op_clock_gettime,
25965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
25975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#ifdef USBI_TIMERFD_AVAILABLE
25985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	.get_timerfd_clockid = op_get_timerfd_clockid,
25995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
26005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
26015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	.device_priv_size = sizeof(struct linux_device_priv),
26025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	.device_handle_priv_size = sizeof(struct linux_device_handle_priv),
26035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	.transfer_priv_size = sizeof(struct linux_transfer_priv),
26045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	.add_iso_packet_size = 0,
26055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
2606