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