1e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev/* 2e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev * Core functions for libusb-compat-0.1 3e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev * Copyright (C) 2008 Daniel Drake <dsd@gentoo.org> 4e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev * Copyright (c) 2000-2003 Johannes Erdfelt <johannes@erdfelt.com> 5e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev * 6e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev * This library is free software; you can redistribute it and/or 7e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev * modify it under the terms of the GNU Lesser General Public 8e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev * License as published by the Free Software Foundation; either 9e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev * version 2.1 of the License, or (at your option) any later version. 10e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev * 11e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev * This library is distributed in the hope that it will be useful, 12e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev * but WITHOUT ANY WARRANTY; without even the implied warranty of 13e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev * Lesser General Public License for more details. 15e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev * 16e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev * You should have received a copy of the GNU Lesser General Public 17e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev * License along with this library; if not, write to the Free Software 18e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 19e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev */ 20e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev 21e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev#include <config.h> 22e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev#include <errno.h> 23e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev#include <stdarg.h> 24e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev#include <stdio.h> 25e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev#include <string.h> 26e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev 27e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev#include <libusb.h> 28e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev 29e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev#include "usb.h" 30e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev#include "usbi.h" 31e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev 32e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishevstatic libusb_context *ctx = NULL; 33e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishevstatic int usb_debug = 0; 34e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev 35e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishevenum usbi_log_level { 36e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev LOG_LEVEL_DEBUG, 37e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev LOG_LEVEL_INFO, 38e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev LOG_LEVEL_WARNING, 39e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev LOG_LEVEL_ERROR, 40e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev}; 41e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev 42e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev#ifdef ENABLE_LOGGING 43e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev#define _usbi_log(level, fmt...) usbi_log(level, __FUNCTION__, fmt) 44e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev#else 45e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev#define _usbi_log(level, fmt...) 46e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev#endif 47e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev 48e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev#ifdef ENABLE_DEBUG_LOGGING 49e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev#define usbi_dbg(fmt...) _usbi_log(LOG_LEVEL_DEBUG, fmt) 50e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev#else 51e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev#define usbi_dbg(fmt...) 52e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev#endif 53e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev 54e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev#define usbi_info(fmt...) _usbi_log(LOG_LEVEL_INFO, fmt) 55e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev#define usbi_warn(fmt...) _usbi_log(LOG_LEVEL_WARNING, fmt) 56e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev#define usbi_err(fmt...) _usbi_log(LOG_LEVEL_ERROR, fmt) 57e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev 58e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor GoulishevAPI_EXPORTED struct usb_bus *usb_busses = NULL; 59e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev 60e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev#define compat_err(e) -(errno=libusb_to_errno(e)) 61e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev 62e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishevstatic int libusb_to_errno(int result) 63e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev{ 64e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev switch (result) { 65e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev case LIBUSB_SUCCESS: 66e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev return 0; 67e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev case LIBUSB_ERROR_IO: 68e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev return EIO; 69e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev case LIBUSB_ERROR_INVALID_PARAM: 70e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev return EINVAL; 71e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev case LIBUSB_ERROR_ACCESS: 72e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev return EACCES; 73e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev case LIBUSB_ERROR_NO_DEVICE: 74e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev return ENXIO; 75e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev case LIBUSB_ERROR_NOT_FOUND: 76e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev return ENOENT; 77e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev case LIBUSB_ERROR_BUSY: 78e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev return EBUSY; 79e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev case LIBUSB_ERROR_TIMEOUT: 80e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev return ETIMEDOUT; 81e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev case LIBUSB_ERROR_OVERFLOW: 82e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev return EOVERFLOW; 83e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev case LIBUSB_ERROR_PIPE: 84e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev return EPIPE; 85e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev case LIBUSB_ERROR_INTERRUPTED: 86e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev return EINTR; 87e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev case LIBUSB_ERROR_NO_MEM: 88e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev return ENOMEM; 89e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev case LIBUSB_ERROR_NOT_SUPPORTED: 90e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev return ENOSYS; 91e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev default: 92e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev return ERANGE; 93e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev } 94e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev} 95e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev 96e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishevstatic void usbi_log(enum usbi_log_level level, const char *function, 97e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev const char *format, ...) 98e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev{ 99e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev va_list args; 100e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev FILE *stream = stdout; 101e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev const char *prefix; 102e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev 103e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev#ifndef ENABLE_DEBUG_LOGGING 104e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev if (!usb_debug) 105e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev return; 106e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev#endif 107e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev 108e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev switch (level) { 109e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev case LOG_LEVEL_INFO: 110e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev prefix = "info"; 111e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev break; 112e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev case LOG_LEVEL_WARNING: 113e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev stream = stderr; 114e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev prefix = "warning"; 115e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev break; 116e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev case LOG_LEVEL_ERROR: 117e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev stream = stderr; 118e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev prefix = "error"; 119e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev break; 120e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev case LOG_LEVEL_DEBUG: 121e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev stream = stderr; 122e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev prefix = "debug"; 123e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev break; 124e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev default: 125e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev stream = stderr; 126e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev prefix = "unknown"; 127e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev break; 128e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev } 129e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev 130e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev fprintf(stream, "libusb-compat %s: %s: ", prefix, function); 131e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev 132e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev va_start (args, format); 133e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev vfprintf(stream, format, args); 134e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev va_end (args); 135e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev 136e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev fprintf(stream, "\n"); 137e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev} 138e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev 139e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor GoulishevAPI_EXPORTED void usb_init(void) 140e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev{ 141e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev int r; 142e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev usbi_dbg(""); 143e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev 144e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev if (!ctx) { 145e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev r = libusb_init(&ctx); 146e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev if (r < 0) { 147e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev usbi_err("initialization failed!"); 148e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev return; 149e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev } 150e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev 151e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev /* usb_set_debug can be called before usb_init */ 152e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev if (usb_debug) 153e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev libusb_set_debug(ctx, 3); 154e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev } 155e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev} 156e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev 157e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor GoulishevAPI_EXPORTED void usb_set_debug(int level) 158e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev{ 159e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev usb_debug = level; 160e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev 161e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev /* usb_set_debug can be called before usb_init */ 162e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev if (ctx) 163e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev libusb_set_debug(ctx, 3); 164e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev} 165e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev 166e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor GoulishevAPI_EXPORTED char *usb_strerror(void) 167e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev{ 168e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev return strerror(errno); 169e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev} 170e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev 171e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishevstatic int find_busses(struct usb_bus **ret) 172e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev{ 173e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev libusb_device **dev_list = NULL; 174e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev struct usb_bus *busses = NULL; 175e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev struct usb_bus *bus; 176e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev int dev_list_len = 0; 177e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev int i; 178e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev int r; 179e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev 180e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev r = libusb_get_device_list(ctx, &dev_list); 181e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev if (r < 0) { 182e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev usbi_err("get_device_list failed with error %d", r); 183e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev return compat_err(r); 184e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev } 185e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev 186e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev if (r == 0) { 187e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev libusb_free_device_list(dev_list, 1); 188e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev /* no buses */ 189e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev return 0; 190e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev } 191e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev 192e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev /* iterate over the device list, identifying the individual busses. 193e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev * we use the location field of the usb_bus structure to store the 194e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev * bus number. */ 195e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev 196e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev dev_list_len = r; 197e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev for (i = 0; i < dev_list_len; i++) { 198e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev libusb_device *dev = dev_list[i]; 199e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev uint8_t bus_num = libusb_get_bus_number(dev); 200e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev 201e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev /* if we already know about it, continue */ 202e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev if (busses) { 203e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev bus = busses; 204e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev int found = 0; 205e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev do { 206e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev if (bus_num == bus->location) { 207e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev found = 1; 208e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev break; 209e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev } 210e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev } while ((bus = bus->next) != NULL); 211e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev if (found) 212e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev continue; 213e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev } 214e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev 215e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev /* add it to the list of busses */ 216e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev bus = malloc(sizeof(*bus)); 217e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev if (!bus) 218e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev goto err; 219e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev 220e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev memset(bus, 0, sizeof(*bus)); 221e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev bus->location = bus_num; 222e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev sprintf(bus->dirname, "%03d", bus_num); 223e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev LIST_ADD(busses, bus); 224e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev } 225e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev 226e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev libusb_free_device_list(dev_list, 1); 227e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev *ret = busses; 228e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev return 0; 229e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev 230e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulisheverr: 231e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev bus = busses; 232e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev while (bus) { 233e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev struct usb_bus *tbus = bus->next; 234e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev free(bus); 235e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev bus = tbus; 236e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev } 237e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev return -ENOMEM; 238e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev} 239e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev 240e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor GoulishevAPI_EXPORTED int usb_find_busses(void) 241e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev{ 242e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev struct usb_bus *new_busses = NULL; 243e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev struct usb_bus *bus; 244e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev int changes = 0; 245e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev int r; 246e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev 247e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev /* libusb-1.0 initialization might have failed, but we can't indicate 248e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev * this with libusb-0.1, so trap that situation here */ 249e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev if (!ctx) 250e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev return 0; 251e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev 252e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev usbi_dbg(""); 253e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev r = find_busses(&new_busses); 254e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev if (r < 0) { 255e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev usbi_err("find_busses failed with error %d", r); 256e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev return r; 257e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev } 258e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev 259e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev /* walk through all busses we already know about, removing duplicates 260e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev * from the new list. if we do not find it in the new list, the bus 261e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev * has been removed. */ 262e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev 263e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev bus = usb_busses; 264e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev while (bus) { 265e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev struct usb_bus *tbus = bus->next; 266e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev struct usb_bus *nbus = new_busses; 267e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev int found = 0; 268e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev usbi_dbg("in loop"); 269e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev 270e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev#if 0 /* (yavor) NO caching */ 271e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev while (nbus) { 272e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev struct usb_bus *tnbus = nbus->next; 273e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev 274e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev if (bus->location == nbus->location) { 275e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev LIST_DEL(new_busses, nbus); 276e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev free(nbus); 277e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev found = 1; 278e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev break; 279e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev } 280e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev nbus = tnbus; 281e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev } 282e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev#endif 283e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev if (!found) { 284e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev /* bus removed */ 285e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev usbi_dbg("bus %d removed", bus->location); 286e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev changes++; 287e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev LIST_DEL(usb_busses, bus); 288e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev free(bus); 289e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev } 290e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev 291e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev bus = tbus; 292e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev } 293e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev 294e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev /* anything remaining in new_busses is a new bus */ 295e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev bus = new_busses; 296e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev while (bus) { 297e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev struct usb_bus *tbus = bus->next; 298e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev usbi_dbg("bus %d added", bus->location); 299e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev LIST_DEL(new_busses, bus); 300e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev LIST_ADD(usb_busses, bus); 301e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev changes++; 302e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev bus = tbus; 303e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev } 304e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev 305e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev return changes; 306e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev} 307e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev 308e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishevstatic int find_devices(libusb_device **dev_list, int dev_list_len, 309e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev struct usb_bus *bus, struct usb_device **ret) 310e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev{ 311e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev struct usb_device *devices = NULL; 312e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev struct usb_device *dev; 313e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev int i; 314e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev 315e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev for (i = 0; i < dev_list_len; i++) { 316e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev libusb_device *newlib_dev = dev_list[i]; 317e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev uint8_t bus_num = libusb_get_bus_number(newlib_dev); 318e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev 319e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev if (bus_num != bus->location) 320e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev continue; 321e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev 322e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev dev = malloc(sizeof(*dev)); 323e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev if (!dev) 324e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev goto err; 325e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev 326e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev /* No need to reference the device now, just take the pointer. We 327e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev * increase the reference count later if we keep the device. */ 328e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev dev->dev = newlib_dev; 329e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev 330e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev dev->bus = bus; 331e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev dev->devnum = libusb_get_device_address(newlib_dev); 332e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev sprintf(dev->filename, "%03d", dev->devnum); 333e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev LIST_ADD(devices, dev); 334e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev } 335e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev 336e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev *ret = devices; 337e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev return 0; 338e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev 339e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulisheverr: 340e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev dev = devices; 341e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev while (dev) { 342e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev struct usb_device *tdev = dev->next; 343e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev free(dev); 344e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev dev = tdev; 345e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev } 346e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev return -ENOMEM; 347e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev} 348e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev 349e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishevstatic void clear_endpoint_descriptor(struct usb_endpoint_descriptor *ep) 350e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev{ 351e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev if (ep->extra) 352e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev free(ep->extra); 353e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev} 354e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev 355e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishevstatic void clear_interface_descriptor(struct usb_interface_descriptor *iface) 356e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev{ 357e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev if (iface->extra) 358e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev free(iface->extra); 359e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev if (iface->endpoint) { 360e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev int i; 361e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev for (i = 0; i < iface->bNumEndpoints; i++) 362e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev clear_endpoint_descriptor(iface->endpoint + i); 363e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev free(iface->endpoint); 364e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev } 365e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev} 366e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev 367e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishevstatic void clear_interface(struct usb_interface *iface) 368e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev{ 369e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev if (iface->altsetting) { 370e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev int i; 371e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev for (i = 0; i < iface->num_altsetting; i++) 372e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev clear_interface_descriptor(iface->altsetting + i); 373e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev free(iface->altsetting); 374e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev } 375e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev} 376e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev 377e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishevstatic void clear_config_descriptor(struct usb_config_descriptor *config) 378e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev{ 379e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev if (config->extra) 380e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev free(config->extra); 381e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev if (config->interface) { 382e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev int i; 383e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev for (i = 0; i < config->bNumInterfaces; i++) 384e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev clear_interface(config->interface + i); 385e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev free(config->interface); 386e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev } 387e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev} 388e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev 389e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishevstatic void clear_device(struct usb_device *dev) 390e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev{ 391e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev int i; 392e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev for (i = 0; i < dev->descriptor.bNumConfigurations; i++) 393e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev clear_config_descriptor(dev->config + i); 394e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev} 395e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev 396e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishevstatic int copy_endpoint_descriptor(struct usb_endpoint_descriptor *dest, 397e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev const struct libusb_endpoint_descriptor *src) 398e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev{ 399e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev memcpy(dest, src, USB_DT_ENDPOINT_AUDIO_SIZE); 400e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev 401e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev dest->extralen = src->extra_length; 402e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev if (src->extra_length) { 403e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev dest->extra = malloc(src->extra_length); 404e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev if (!dest->extra) 405e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev return -ENOMEM; 406e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev memcpy(dest->extra, src->extra, src->extra_length); 407e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev } 408e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev 409e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev return 0; 410e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev} 411e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev 412e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishevstatic int copy_interface_descriptor(struct usb_interface_descriptor *dest, 413e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev const struct libusb_interface_descriptor *src) 414e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev{ 415e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev int i; 416e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev int num_endpoints = src->bNumEndpoints; 417e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev size_t alloc_size = sizeof(struct usb_endpoint_descriptor) * num_endpoints; 418e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev 419e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev memcpy(dest, src, USB_DT_INTERFACE_SIZE); 420e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev dest->endpoint = malloc(alloc_size); 421e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev if (!dest->endpoint) 422e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev return -ENOMEM; 423e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev memset(dest->endpoint, 0, alloc_size); 424e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev 425e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev for (i = 0; i < num_endpoints; i++) { 426e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev int r = copy_endpoint_descriptor(dest->endpoint + i, &src->endpoint[i]); 427e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev if (r < 0) { 428e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev clear_interface_descriptor(dest); 429e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev return r; 430e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev } 431e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev } 432e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev 433e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev dest->extralen = src->extra_length; 434e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev if (src->extra_length) { 435e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev dest->extra = malloc(src->extra_length); 436e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev if (!dest->extra) { 437e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev clear_interface_descriptor(dest); 438e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev return -ENOMEM; 439e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev } 440e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev memcpy(dest->extra, src->extra, src->extra_length); 441e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev } 442e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev 443e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev return 0; 444e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev} 445e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev 446e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishevstatic int copy_interface(struct usb_interface *dest, 447e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev const struct libusb_interface *src) 448e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev{ 449e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev int i; 450e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev int num_altsetting = src->num_altsetting; 451e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev size_t alloc_size = sizeof(struct usb_interface_descriptor) 452e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev * num_altsetting; 453e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev 454e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev dest->num_altsetting = num_altsetting; 455e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev dest->altsetting = malloc(alloc_size); 456e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev if (!dest->altsetting) 457e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev return -ENOMEM; 458e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev memset(dest->altsetting, 0, alloc_size); 459e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev 460e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev for (i = 0; i < num_altsetting; i++) { 461e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev int r = copy_interface_descriptor(dest->altsetting + i, 462e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev &src->altsetting[i]); 463e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev if (r < 0) { 464e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev clear_interface(dest); 465e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev return r; 466e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev } 467e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev } 468e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev 469e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev return 0; 470e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev} 471e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev 472e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishevstatic int copy_config_descriptor(struct usb_config_descriptor *dest, 473e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev const struct libusb_config_descriptor *src) 474e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev{ 475e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev int i; 476e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev int num_interfaces = src->bNumInterfaces; 477e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev size_t alloc_size = sizeof(struct usb_interface) * num_interfaces; 478e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev 479e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev memcpy(dest, src, USB_DT_CONFIG_SIZE); 480e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev dest->interface = malloc(alloc_size); 481e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev if (!dest->interface) 482e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev return -ENOMEM; 483e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev memset(dest->interface, 0, alloc_size); 484e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev 485e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev for (i = 0; i < num_interfaces; i++) { 486e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev int r = copy_interface(dest->interface + i, &src->interface[i]); 487e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev if (r < 0) { 488e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev clear_config_descriptor(dest); 489e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev return r; 490e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev } 491e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev } 492e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev 493e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev dest->extralen = src->extra_length; 494e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev if (src->extra_length) { 495e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev dest->extra = malloc(src->extra_length); 496e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev if (!dest->extra) { 497e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev clear_config_descriptor(dest); 498e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev return -ENOMEM; 499e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev } 500e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev memcpy(dest->extra, src->extra, src->extra_length); 501e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev } 502e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev 503e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev return 0; 504e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev} 505e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev 506e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishevstatic int initialize_device(struct usb_device *dev) 507e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev{ 508e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev libusb_device *newlib_dev = dev->dev; 509e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev int num_configurations; 510e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev size_t alloc_size; 511e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev int r; 512e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev int i; 513e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev 514e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev /* device descriptor is identical in both libs */ 515e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev r = libusb_get_device_descriptor(newlib_dev, 516e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev (struct libusb_device_descriptor *) &dev->descriptor); 517e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev if (r < 0) { 518e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev usbi_err("error %d getting device descriptor", r); 519e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev return compat_err(r); 520e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev } 521e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev 522e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev num_configurations = dev->descriptor.bNumConfigurations; 523e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev alloc_size = sizeof(struct usb_config_descriptor) * num_configurations; 524e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev dev->config = malloc(alloc_size); 525e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev if (!dev->config) 526e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev return -ENOMEM; 527e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev memset(dev->config, 0, alloc_size); 528e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev 529e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev /* even though structures are identical, we can't just use libusb-1.0's 530e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev * config descriptors because we have to store all configurations in 531e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev * a single flat memory area (libusb-1.0 provides separate allocations). 532e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev * we hand-copy libusb-1.0's descriptors into our own structures. */ 533e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev for (i = 0; i < num_configurations; i++) { 534e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev struct libusb_config_descriptor *newlib_config; 535e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev r = libusb_get_config_descriptor(newlib_dev, i, &newlib_config); 536e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev if (r < 0) { 537e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev clear_device(dev); 538e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev free(dev->config); 539e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev return compat_err(r); 540e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev } 541e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev r = copy_config_descriptor(dev->config + i, newlib_config); 542e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev libusb_free_config_descriptor(newlib_config); 543e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev if (r < 0) { 544e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev clear_device(dev); 545e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev free(dev->config); 546e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev return r; 547e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev } 548e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev } 549e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev 550e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev /* libusb doesn't implement this and it doesn't seem that important. If 551e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev * someone asks for it, we can implement it in v1.1 or later. */ 552e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev dev->num_children = 0; 553e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev dev->children = NULL; 554e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev 555e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev libusb_ref_device(newlib_dev); 556e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev return 0; 557e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev} 558e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev 559e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishevstatic void free_device(struct usb_device *dev) 560e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev{ 561e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev clear_device(dev); 562e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev libusb_unref_device(dev->dev); 563e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev free(dev); 564e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev} 565e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev 566e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor GoulishevAPI_EXPORTED int usb_find_devices(void) 567e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev{ 568e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev struct usb_bus *bus; 569e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev libusb_device **dev_list; 570e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev int dev_list_len; 571e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev int r; 572e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev int changes = 0; 573e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev 574e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev /* libusb-1.0 initialization might have failed, but we can't indicate 575e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev * this with libusb-0.1, so trap that situation here */ 576e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev if (!ctx) 577e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev return 0; 578e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev 579e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev usbi_dbg(""); 580e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev dev_list_len = libusb_get_device_list(ctx, &dev_list); 581e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev if (dev_list_len < 0) 582e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev return compat_err(dev_list_len); 583e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev 584e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev for (bus = usb_busses; bus; bus = bus->next) { 585e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev struct usb_device *new_devices = NULL; 586e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev struct usb_device *dev; 587e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev 588e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev r = find_devices(dev_list, dev_list_len, bus, &new_devices); 589e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev if (r < 0) { 590e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev libusb_free_device_list(dev_list, 1); 591e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev return r; 592e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev } 593e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev 594e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev /* walk through the devices we already know about, removing duplicates 595e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev * from the new list. if we do not find it in the new list, the device 596e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev * has been removed. */ 597e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev dev = bus->devices; 598e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev while (dev) { 599e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev int found = 0; 600e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev struct usb_device *tdev = dev->next; 601e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev struct usb_device *ndev = new_devices; 602e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev 603e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev while (ndev) { 604e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev if (ndev->devnum == dev->devnum) { 605e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev LIST_DEL(new_devices, ndev); 606e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev free(ndev); 607e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev found = 1; 608e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev break; 609e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev } 610e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev ndev = ndev->next; 611e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev } 612e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev 613e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev if (!found) { 614e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev usbi_dbg("device %d.%d removed", 615e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev dev->bus->location, dev->devnum); 616e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev LIST_DEL(bus->devices, dev); 617e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev free_device(dev); 618e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev changes++; 619e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev } 620e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev 621e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev dev = tdev; 622e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev } 623e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev 624e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev /* anything left in new_devices is a new device */ 625e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev dev = new_devices; 626e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev while (dev) { 627e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev struct usb_device *tdev = dev->next; 628e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev r = initialize_device(dev); 629e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev if (r < 0) { 630e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev usbi_err("couldn't initialize device %d.%d (error %d)", 631e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev dev->bus->location, dev->devnum, r); 632e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev dev = tdev; 633e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev continue; 634e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev } 635e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev usbi_dbg("device %d.%d added", dev->bus->location, dev->devnum); 636e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev LIST_DEL(new_devices, dev); 637e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev LIST_ADD(bus->devices, dev); 638e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev changes++; 639e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev dev = tdev; 640e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev } 641e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev } 642e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev 643e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev libusb_free_device_list(dev_list, 1); 644e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev return changes; 645e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev} 646e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev 647e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor GoulishevAPI_EXPORTED struct usb_bus *usb_get_busses(void) 648e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev{ 649e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev return usb_busses; 650e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev} 651e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev 652e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor GoulishevAPI_EXPORTED usb_dev_handle *usb_open(struct usb_device *dev) 653e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev{ 654e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev int r; 655e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev usbi_dbg(""); 656e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev 657e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev usb_dev_handle *udev = malloc(sizeof(*udev)); 658e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev if (!udev) 659e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev return NULL; 660e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev 661e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev r = libusb_open((libusb_device *) dev->dev, &udev->handle); 662e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev if (r < 0) { 663e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev usbi_err("could not open device, error %d", r); 664e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev free(udev); 665e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev errno = libusb_to_errno(r); 666e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev return NULL; 667e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev } 668e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev 669e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev udev->last_claimed_interface = -1; 670e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev udev->device = dev; 671e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev return udev; 672e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev} 673e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev 674e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor GoulishevAPI_EXPORTED int usb_close(usb_dev_handle *dev) 675e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev{ 676e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev usbi_dbg(""); 677e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev libusb_close(dev->handle); 678e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev free(dev); 679e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev return 0; 680e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev} 681e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev 682e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor GoulishevAPI_EXPORTED struct usb_device *usb_device(usb_dev_handle *dev) 683e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev{ 684e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev return dev->device; 685e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev} 686e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev 687e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor GoulishevAPI_EXPORTED int usb_set_configuration(usb_dev_handle *dev, int configuration) 688e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev{ 689e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev usbi_dbg("configuration %d", configuration); 690e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev return compat_err(libusb_set_configuration(dev->handle, configuration)); 691e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev} 692e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev 693e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor GoulishevAPI_EXPORTED int usb_claim_interface(usb_dev_handle *dev, int interface) 694e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev{ 695e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev int r; 696e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev usbi_dbg("interface %d", interface); 697e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev 698e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev r = libusb_claim_interface(dev->handle, interface); 699e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev if (r == 0) { 700e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev dev->last_claimed_interface = interface; 701e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev return 0; 702e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev } 703e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev 704e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev return compat_err(r); 705e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev} 706e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev 707e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor GoulishevAPI_EXPORTED int usb_release_interface(usb_dev_handle *dev, int interface) 708e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev{ 709e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev int r; 710e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev usbi_dbg("interface %d", interface); 711e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev 712e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev r = libusb_release_interface(dev->handle, interface); 713e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev if (r == 0) 714e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev dev->last_claimed_interface = -1; 715e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev 716e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev return compat_err(r); 717e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev} 718e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev 719e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor GoulishevAPI_EXPORTED int usb_set_altinterface(usb_dev_handle *dev, int alternate) 720e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev{ 721e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev usbi_dbg("alternate %d", alternate); 722e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev if (dev->last_claimed_interface < 0) 723e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev return -(errno=EINVAL); 724e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev 725e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev return compat_err(libusb_set_interface_alt_setting(dev->handle, 726e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev dev->last_claimed_interface, alternate)); 727e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev} 728e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev 729e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor GoulishevAPI_EXPORTED int usb_resetep(usb_dev_handle *dev, unsigned int ep) 730e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev{ 731e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev return compat_err(usb_clear_halt(dev, ep)); 732e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev} 733e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev 734e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor GoulishevAPI_EXPORTED int usb_clear_halt(usb_dev_handle *dev, unsigned int ep) 735e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev{ 736e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev usbi_dbg("endpoint %x", ep); 737e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev return compat_err(libusb_clear_halt(dev->handle, ep & 0xff)); 738e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev} 739e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev 740e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor GoulishevAPI_EXPORTED int usb_reset(usb_dev_handle *dev) 741e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev{ 742e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev usbi_dbg(""); 743e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev return compat_err(libusb_reset_device(dev->handle)); 744e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev} 745e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev 746e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishevstatic int usb_bulk_io(usb_dev_handle *dev, int ep, char *bytes, 747e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev int size, int timeout) 748e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev{ 749e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev int actual_length; 750e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev int r; 751e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev usbi_dbg("endpoint %x size %d timeout %d", ep, size, timeout); 752e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev r = libusb_bulk_transfer(dev->handle, ep & 0xff, bytes, size, 753e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev &actual_length, timeout); 754e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev 755e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev /* if we timed out but did transfer some data, report as successful short 756e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev * read. FIXME: is this how libusb-0.1 works? */ 757e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev if (r == 0 || (r == LIBUSB_ERROR_TIMEOUT && actual_length > 0)) 758e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev return actual_length; 759e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev 760e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev return compat_err(r); 761e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev} 762e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev 763e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor GoulishevAPI_EXPORTED int usb_bulk_read(usb_dev_handle *dev, int ep, char *bytes, 764e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev int size, int timeout) 765e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev{ 766e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev if (!(ep & USB_ENDPOINT_IN)) { 767e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev /* libusb-0.1 will strangely fix up a read request from endpoint 768e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev * 0x01 to be from endpoint 0x81. do the same thing here, but 769e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev * warn about this silly behaviour. */ 770e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev usbi_warn("endpoint %x is missing IN direction bit, fixing"); 771e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev ep |= USB_ENDPOINT_IN; 772e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev } 773e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev 774e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev return usb_bulk_io(dev, ep, bytes, size, timeout); 775e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev} 776e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev 777e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor GoulishevAPI_EXPORTED int usb_bulk_write(usb_dev_handle *dev, int ep, char *bytes, 778e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev int size, int timeout) 779e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev{ 780e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev if (ep & USB_ENDPOINT_IN) { 781e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev /* libusb-0.1 on BSD strangely fix up a write request to endpoint 782e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev * 0x81 to be to endpoint 0x01. do the same thing here, but 783e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev * warn about this silly behaviour. */ 784e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev usbi_warn("endpoint %x has excessive IN direction bit, fixing"); 785e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev ep &= ~USB_ENDPOINT_IN; 786e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev } 787e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev 788e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev return usb_bulk_io(dev, ep, bytes, size, timeout); 789e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev} 790e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev 791e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishevstatic int usb_interrupt_io(usb_dev_handle *dev, int ep, char *bytes, 792e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev int size, int timeout) 793e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev{ 794e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev int actual_length; 795e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev int r; 796e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev usbi_dbg("endpoint %x size %d timeout %d", ep, size, timeout); 797e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev r = libusb_interrupt_transfer(dev->handle, ep & 0xff, bytes, size, 798e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev &actual_length, timeout); 799e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev 800e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev /* if we timed out but did transfer some data, report as successful short 801e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev * read. FIXME: is this how libusb-0.1 works? */ 802e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev if (r == 0 || (r == LIBUSB_ERROR_TIMEOUT && actual_length > 0)) 803e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev return actual_length; 804e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev 805e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev return compat_err(r); 806e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev} 807e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev 808e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor GoulishevAPI_EXPORTED int usb_interrupt_read(usb_dev_handle *dev, int ep, char *bytes, 809e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev int size, int timeout) 810e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev{ 811e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev if (!(ep & USB_ENDPOINT_IN)) { 812e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev /* libusb-0.1 will strangely fix up a read request from endpoint 813e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev * 0x01 to be from endpoint 0x81. do the same thing here, but 814e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev * warn about this silly behaviour. */ 815e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev usbi_warn("endpoint %x is missing IN direction bit, fixing"); 816e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev ep |= USB_ENDPOINT_IN; 817e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev } 818e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev return usb_interrupt_io(dev, ep, bytes, size, timeout); 819e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev} 820e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev 821e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor GoulishevAPI_EXPORTED int usb_interrupt_write(usb_dev_handle *dev, int ep, char *bytes, 822e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev int size, int timeout) 823e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev{ 824e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev if (ep & USB_ENDPOINT_IN) { 825e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev /* libusb-0.1 on BSD strangely fix up a write request to endpoint 826e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev * 0x81 to be to endpoint 0x01. do the same thing here, but 827e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev * warn about this silly behaviour. */ 828e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev usbi_warn("endpoint %x has excessive IN direction bit, fixing"); 829e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev ep &= ~USB_ENDPOINT_IN; 830e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev } 831e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev 832e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev return usb_interrupt_io(dev, ep, bytes, size, timeout); 833e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev} 834e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev 835e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor GoulishevAPI_EXPORTED int usb_control_msg(usb_dev_handle *dev, int bmRequestType, 836e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev int bRequest, int wValue, int wIndex, char *bytes, int size, int timeout) 837e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev{ 838e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev int r; 839e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev usbi_dbg("RQT=%x RQ=%x V=%x I=%x len=%d timeout=%d", bmRequestType, 840e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev bRequest, wValue, wIndex, size, timeout); 841e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev 842e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev r = libusb_control_transfer(dev->handle, bmRequestType & 0xff, 843e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev bRequest & 0xff, wValue & 0xffff, wIndex & 0xffff, bytes, size & 0xffff, 844e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev timeout); 845e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev 846e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev if (r >= 0) 847e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev return r; 848e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev 849e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev return compat_err(r); 850e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev} 851e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev 852e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor GoulishevAPI_EXPORTED int usb_get_string(usb_dev_handle *dev, int desc_index, int langid, 853e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev char *buf, size_t buflen) 854e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev{ 855e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev int r; 856e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev r = libusb_get_string_descriptor(dev->handle, desc_index & 0xff, 857e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev langid & 0xffff, buf, (int) buflen); 858e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev if (r >= 0) 859e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev return r; 860e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev return compat_err(r); 861e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev} 862e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev 863e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor GoulishevAPI_EXPORTED int usb_get_string_simple(usb_dev_handle *dev, int desc_index, 864e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev char *buf, size_t buflen) 865e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev{ 866e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev int r; 867e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev r = libusb_get_string_descriptor_ascii(dev->handle, desc_index & 0xff, 868e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev buf, (int) buflen); 869e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev if (r >= 0) 870e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev return r; 871e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev return compat_err(r); 872e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev} 873e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev 874e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor GoulishevAPI_EXPORTED int usb_get_descriptor(usb_dev_handle *dev, unsigned char type, 875e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev unsigned char desc_index, void *buf, int size) 876e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev{ 877e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev int r; 878e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev r = libusb_get_descriptor(dev->handle, type, desc_index, buf, size); 879e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev if (r >= 0) 880e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev return r; 881e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev return compat_err(r); 882e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev} 883e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev 884e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor GoulishevAPI_EXPORTED int usb_get_descriptor_by_endpoint(usb_dev_handle *dev, int ep, 885e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev unsigned char type, unsigned char desc_index, void *buf, int size) 886e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev{ 887e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev /* this function doesn't make much sense - the specs don't talk about 888e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev * getting a descriptor "by endpoint". libusb-1.0 does not provide this 889e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev * functionality so we just send a control message directly */ 890e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev int r; 891e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev r = libusb_control_transfer(dev->handle, 892e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev LIBUSB_ENDPOINT_IN | (ep & 0xff), LIBUSB_REQUEST_GET_DESCRIPTOR, 893e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev (type << 8) | desc_index, 0, buf, size, 1000); 894e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev if (r >= 0) 895e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev return r; 896e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev return compat_err(r); 897e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev} 898e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev 899e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor GoulishevAPI_EXPORTED int usb_get_driver_np(usb_dev_handle *dev, int interface, 900e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev char *name, unsigned int namelen) 901e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev{ 902e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev int r = libusb_kernel_driver_active(dev->handle, interface); 903e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev if (r == 1) { 904e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev /* libusb-1.0 doesn't expose driver name, so fill in a dummy value */ 905e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev snprintf(name, namelen, "dummy"); 906e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev return 0; 907e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev } else if (r == 0) { 908e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev return -(errno=ENODATA); 909e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev } else { 910e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev return compat_err(r); 911e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev } 912e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev} 913e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev 914e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor GoulishevAPI_EXPORTED int usb_detach_kernel_driver_np(usb_dev_handle *dev, int interface) 915e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev{ 916e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev return compat_err(libusb_detach_kernel_driver(dev->handle, interface)); 917e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev} 918e9a683104ef3f40d38459c0ca62a2d46f20b0714Yavor Goulishev 919