1a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor/*
2a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor * Core functions for libusb-compat-0.1
3a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor * Copyright (C) 2008 Daniel Drake <dsd@gentoo.org>
4a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor * Copyright (c) 2000-2003 Johannes Erdfelt <johannes@erdfelt.com>
5a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor *
6a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor * This library is free software; you can redistribute it and/or
7a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor * modify it under the terms of the GNU Lesser General Public
8a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor * License as published by the Free Software Foundation; either
9a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor * version 2.1 of the License, or (at your option) any later version.
10a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor *
11a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor * This library is distributed in the hope that it will be useful,
12a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor * but WITHOUT ANY WARRANTY; without even the implied warranty of
13a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor * Lesser General Public License for more details.
15a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor *
16a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor * You should have received a copy of the GNU Lesser General Public
17a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor * License along with this library; if not, write to the Free Software
18a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19fa69fc19121da3fc5673ccc00d4e8afa5b540a4fDouglas Gregor */
20a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor
21a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor#include <config.h>
22a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor#include <errno.h>
23a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor#include <stdarg.h>
24a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor#include <stdio.h>
25a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor#include <string.h>
265100135ecf29d4246e6bd34318da9eb22c16b86aDouglas Gregor
27a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor#include <libusb.h>
28a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor
298229d22e6449851b89361bf2f41804557328be63Rafael Espindola#include "usb.h"
301d32133b44487d9e98412e373d693416b05920bbNAKAMURA Takumi#include "usbi.h"
31a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor
32a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregorstatic libusb_context *ctx = NULL;
33a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregorstatic int usb_debug = 0;
34a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor
35a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregorenum usbi_log_level {
36a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor	LOG_LEVEL_DEBUG,
37a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor	LOG_LEVEL_INFO,
38a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor	LOG_LEVEL_WARNING,
39a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor	LOG_LEVEL_ERROR,
40a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor};
41a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor
42a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor#ifdef ENABLE_LOGGING
43a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor#define _usbi_log(level, fmt...) usbi_log(level, __FUNCTION__, fmt)
44a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor#else
45a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor#define _usbi_log(level, fmt...)
46a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor#endif
471a49d97d762570027863e9209af81d445e4f1502Douglas Gregor
48a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor#ifdef ENABLE_DEBUG_LOGGING
49a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor#define usbi_dbg(fmt...) _usbi_log(LOG_LEVEL_DEBUG, fmt)
50a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor#else
51a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor#define usbi_dbg(fmt...)
52a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor#endif
53a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor
54a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor#define usbi_info(fmt...) _usbi_log(LOG_LEVEL_INFO, fmt)
55a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor#define usbi_warn(fmt...) _usbi_log(LOG_LEVEL_WARNING, fmt)
56a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor#define usbi_err(fmt...) _usbi_log(LOG_LEVEL_ERROR, fmt)
57a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor
58a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas GregorAPI_EXPORTED struct usb_bus *usb_busses = NULL;
59a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor
60a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor#define compat_err(e) -(errno=libusb_to_errno(e))
61a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor
621a49d97d762570027863e9209af81d445e4f1502Douglas Gregorstatic int libusb_to_errno(int result)
631a49d97d762570027863e9209af81d445e4f1502Douglas Gregor{
641a49d97d762570027863e9209af81d445e4f1502Douglas Gregor	switch (result) {
651a49d97d762570027863e9209af81d445e4f1502Douglas Gregor	case LIBUSB_SUCCESS:
661a49d97d762570027863e9209af81d445e4f1502Douglas Gregor		return 0;
671a49d97d762570027863e9209af81d445e4f1502Douglas Gregor	case LIBUSB_ERROR_IO:
681a49d97d762570027863e9209af81d445e4f1502Douglas Gregor		return EIO;
691a49d97d762570027863e9209af81d445e4f1502Douglas Gregor	case LIBUSB_ERROR_INVALID_PARAM:
701a49d97d762570027863e9209af81d445e4f1502Douglas Gregor		return EINVAL;
711a49d97d762570027863e9209af81d445e4f1502Douglas Gregor	case LIBUSB_ERROR_ACCESS:
721a49d97d762570027863e9209af81d445e4f1502Douglas Gregor		return EACCES;
731a49d97d762570027863e9209af81d445e4f1502Douglas Gregor	case LIBUSB_ERROR_NO_DEVICE:
741a49d97d762570027863e9209af81d445e4f1502Douglas Gregor		return ENXIO;
751a49d97d762570027863e9209af81d445e4f1502Douglas Gregor	case LIBUSB_ERROR_NOT_FOUND:
761a49d97d762570027863e9209af81d445e4f1502Douglas Gregor		return ENOENT;
771a49d97d762570027863e9209af81d445e4f1502Douglas Gregor	case LIBUSB_ERROR_BUSY:
781a49d97d762570027863e9209af81d445e4f1502Douglas Gregor		return EBUSY;
791a49d97d762570027863e9209af81d445e4f1502Douglas Gregor	case LIBUSB_ERROR_TIMEOUT:
801a49d97d762570027863e9209af81d445e4f1502Douglas Gregor		return ETIMEDOUT;
811a49d97d762570027863e9209af81d445e4f1502Douglas Gregor	case LIBUSB_ERROR_OVERFLOW:
821a49d97d762570027863e9209af81d445e4f1502Douglas Gregor		return EOVERFLOW;
831a49d97d762570027863e9209af81d445e4f1502Douglas Gregor	case LIBUSB_ERROR_PIPE:
841a49d97d762570027863e9209af81d445e4f1502Douglas Gregor		return EPIPE;
851a49d97d762570027863e9209af81d445e4f1502Douglas Gregor	case LIBUSB_ERROR_INTERRUPTED:
861a49d97d762570027863e9209af81d445e4f1502Douglas Gregor		return EINTR;
871a49d97d762570027863e9209af81d445e4f1502Douglas Gregor	case LIBUSB_ERROR_NO_MEM:
881a49d97d762570027863e9209af81d445e4f1502Douglas Gregor		return ENOMEM;
891a49d97d762570027863e9209af81d445e4f1502Douglas Gregor	case LIBUSB_ERROR_NOT_SUPPORTED:
901a49d97d762570027863e9209af81d445e4f1502Douglas Gregor		return ENOSYS;
911a49d97d762570027863e9209af81d445e4f1502Douglas Gregor	default:
921a49d97d762570027863e9209af81d445e4f1502Douglas Gregor		return ERANGE;
931a49d97d762570027863e9209af81d445e4f1502Douglas Gregor	}
941a49d97d762570027863e9209af81d445e4f1502Douglas Gregor}
951a49d97d762570027863e9209af81d445e4f1502Douglas Gregor
961a49d97d762570027863e9209af81d445e4f1502Douglas Gregorstatic void usbi_log(enum usbi_log_level level, const char *function,
971a49d97d762570027863e9209af81d445e4f1502Douglas Gregor	const char *format, ...)
981a49d97d762570027863e9209af81d445e4f1502Douglas Gregor{
991a49d97d762570027863e9209af81d445e4f1502Douglas Gregor	va_list args;
1001a49d97d762570027863e9209af81d445e4f1502Douglas Gregor	FILE *stream = stdout;
1011a49d97d762570027863e9209af81d445e4f1502Douglas Gregor	const char *prefix;
1021a49d97d762570027863e9209af81d445e4f1502Douglas Gregor
1031a49d97d762570027863e9209af81d445e4f1502Douglas Gregor#ifndef ENABLE_DEBUG_LOGGING
1041a49d97d762570027863e9209af81d445e4f1502Douglas Gregor	if (!usb_debug)
1051a49d97d762570027863e9209af81d445e4f1502Douglas Gregor		return;
1061a49d97d762570027863e9209af81d445e4f1502Douglas Gregor#endif
1071a49d97d762570027863e9209af81d445e4f1502Douglas Gregor
1081a49d97d762570027863e9209af81d445e4f1502Douglas Gregor	switch (level) {
1091a49d97d762570027863e9209af81d445e4f1502Douglas Gregor	case LOG_LEVEL_INFO:
1101a49d97d762570027863e9209af81d445e4f1502Douglas Gregor		prefix = "info";
1111a49d97d762570027863e9209af81d445e4f1502Douglas Gregor		break;
1121a49d97d762570027863e9209af81d445e4f1502Douglas Gregor	case LOG_LEVEL_WARNING:
1131a49d97d762570027863e9209af81d445e4f1502Douglas Gregor		stream = stderr;
1141a49d97d762570027863e9209af81d445e4f1502Douglas Gregor		prefix = "warning";
1151a49d97d762570027863e9209af81d445e4f1502Douglas Gregor		break;
1161a49d97d762570027863e9209af81d445e4f1502Douglas Gregor	case LOG_LEVEL_ERROR:
1171a49d97d762570027863e9209af81d445e4f1502Douglas Gregor		stream = stderr;
1181a49d97d762570027863e9209af81d445e4f1502Douglas Gregor		prefix = "error";
1191a49d97d762570027863e9209af81d445e4f1502Douglas Gregor		break;
1201a49d97d762570027863e9209af81d445e4f1502Douglas Gregor	case LOG_LEVEL_DEBUG:
121677e15ffee2ecc9c1c8f46fd77cab4b5afb59640Douglas Gregor		stream = stderr;
1221a49d97d762570027863e9209af81d445e4f1502Douglas Gregor		prefix = "debug";
123fa69fc19121da3fc5673ccc00d4e8afa5b540a4fDouglas Gregor		break;
124188bdcd1aaf5e9f457cec6851707d7dc3e7bbb15Douglas Gregor	default:
1251a49d97d762570027863e9209af81d445e4f1502Douglas Gregor		stream = stderr;
1261a49d97d762570027863e9209af81d445e4f1502Douglas Gregor		prefix = "unknown";
1271a49d97d762570027863e9209af81d445e4f1502Douglas Gregor		break;
1281a49d97d762570027863e9209af81d445e4f1502Douglas Gregor	}
1291a49d97d762570027863e9209af81d445e4f1502Douglas Gregor
1301a49d97d762570027863e9209af81d445e4f1502Douglas Gregor	fprintf(stream, "libusb-compat %s: %s: ", prefix, function);
1311a49d97d762570027863e9209af81d445e4f1502Douglas Gregor
1321a49d97d762570027863e9209af81d445e4f1502Douglas Gregor	va_start (args, format);
1331a49d97d762570027863e9209af81d445e4f1502Douglas Gregor	vfprintf(stream, format, args);
1341a49d97d762570027863e9209af81d445e4f1502Douglas Gregor	va_end (args);
1351a49d97d762570027863e9209af81d445e4f1502Douglas Gregor
1361a49d97d762570027863e9209af81d445e4f1502Douglas Gregor	fprintf(stream, "\n");
1371a49d97d762570027863e9209af81d445e4f1502Douglas Gregor}
1381a49d97d762570027863e9209af81d445e4f1502Douglas Gregor
1391a49d97d762570027863e9209af81d445e4f1502Douglas GregorAPI_EXPORTED void usb_init(void)
1401a49d97d762570027863e9209af81d445e4f1502Douglas Gregor{
1411a49d97d762570027863e9209af81d445e4f1502Douglas Gregor	int r;
1421a49d97d762570027863e9209af81d445e4f1502Douglas Gregor	usbi_dbg("");
1431a49d97d762570027863e9209af81d445e4f1502Douglas Gregor
1441a49d97d762570027863e9209af81d445e4f1502Douglas Gregor	if (!ctx) {
1451a49d97d762570027863e9209af81d445e4f1502Douglas Gregor		r = libusb_init(&ctx);
1461a49d97d762570027863e9209af81d445e4f1502Douglas Gregor		if (r < 0) {
1471a49d97d762570027863e9209af81d445e4f1502Douglas Gregor			usbi_err("initialization failed!");
1481a49d97d762570027863e9209af81d445e4f1502Douglas Gregor			return;
1491a49d97d762570027863e9209af81d445e4f1502Douglas Gregor		}
1501a49d97d762570027863e9209af81d445e4f1502Douglas Gregor
1511a49d97d762570027863e9209af81d445e4f1502Douglas Gregor		/* usb_set_debug can be called before usb_init */
1521a49d97d762570027863e9209af81d445e4f1502Douglas Gregor		if (usb_debug)
1531a49d97d762570027863e9209af81d445e4f1502Douglas Gregor			libusb_set_debug(ctx, 3);
1541a49d97d762570027863e9209af81d445e4f1502Douglas Gregor	}
1551a49d97d762570027863e9209af81d445e4f1502Douglas Gregor}
1561a49d97d762570027863e9209af81d445e4f1502Douglas Gregor
1571a49d97d762570027863e9209af81d445e4f1502Douglas GregorAPI_EXPORTED void usb_set_debug(int level)
1581a49d97d762570027863e9209af81d445e4f1502Douglas Gregor{
1591a49d97d762570027863e9209af81d445e4f1502Douglas Gregor	usb_debug = level;
1601a49d97d762570027863e9209af81d445e4f1502Douglas Gregor
1611a49d97d762570027863e9209af81d445e4f1502Douglas Gregor	/* usb_set_debug can be called before usb_init */
1621a49d97d762570027863e9209af81d445e4f1502Douglas Gregor	if (ctx)
1631a49d97d762570027863e9209af81d445e4f1502Douglas Gregor		libusb_set_debug(ctx, 3);
1641a49d97d762570027863e9209af81d445e4f1502Douglas Gregor}
1651a49d97d762570027863e9209af81d445e4f1502Douglas Gregor
1661a49d97d762570027863e9209af81d445e4f1502Douglas GregorAPI_EXPORTED char *usb_strerror(void)
1671a49d97d762570027863e9209af81d445e4f1502Douglas Gregor{
1681a49d97d762570027863e9209af81d445e4f1502Douglas Gregor	return strerror(errno);
1691a49d97d762570027863e9209af81d445e4f1502Douglas Gregor}
1701a49d97d762570027863e9209af81d445e4f1502Douglas Gregor
1711a49d97d762570027863e9209af81d445e4f1502Douglas Gregorstatic int find_busses(struct usb_bus **ret)
1721a49d97d762570027863e9209af81d445e4f1502Douglas Gregor{
1731a49d97d762570027863e9209af81d445e4f1502Douglas Gregor	libusb_device **dev_list = NULL;
1741a49d97d762570027863e9209af81d445e4f1502Douglas Gregor	struct usb_bus *busses = NULL;
1751a49d97d762570027863e9209af81d445e4f1502Douglas Gregor	struct usb_bus *bus;
176677e15ffee2ecc9c1c8f46fd77cab4b5afb59640Douglas Gregor	int dev_list_len = 0;
177677e15ffee2ecc9c1c8f46fd77cab4b5afb59640Douglas Gregor	int i;
178677e15ffee2ecc9c1c8f46fd77cab4b5afb59640Douglas Gregor	int r;
179677e15ffee2ecc9c1c8f46fd77cab4b5afb59640Douglas Gregor
180677e15ffee2ecc9c1c8f46fd77cab4b5afb59640Douglas Gregor	r = libusb_get_device_list(ctx, &dev_list);
181677e15ffee2ecc9c1c8f46fd77cab4b5afb59640Douglas Gregor	if (r < 0) {
182677e15ffee2ecc9c1c8f46fd77cab4b5afb59640Douglas Gregor		usbi_err("get_device_list failed with error %d", r);
183677e15ffee2ecc9c1c8f46fd77cab4b5afb59640Douglas Gregor		return compat_err(r);
184677e15ffee2ecc9c1c8f46fd77cab4b5afb59640Douglas Gregor	}
185677e15ffee2ecc9c1c8f46fd77cab4b5afb59640Douglas Gregor
186677e15ffee2ecc9c1c8f46fd77cab4b5afb59640Douglas Gregor	if (r == 0) {
1871a49d97d762570027863e9209af81d445e4f1502Douglas Gregor		libusb_free_device_list(dev_list, 1);
1881a49d97d762570027863e9209af81d445e4f1502Douglas Gregor		/* no buses */
1891a49d97d762570027863e9209af81d445e4f1502Douglas Gregor		return 0;
190677e15ffee2ecc9c1c8f46fd77cab4b5afb59640Douglas Gregor	}
191677e15ffee2ecc9c1c8f46fd77cab4b5afb59640Douglas Gregor
1921a49d97d762570027863e9209af81d445e4f1502Douglas Gregor	/* iterate over the device list, identifying the individual busses.
1931a49d97d762570027863e9209af81d445e4f1502Douglas Gregor	 * we use the location field of the usb_bus structure to store the
1941a49d97d762570027863e9209af81d445e4f1502Douglas Gregor	 * bus number. */
1951a49d97d762570027863e9209af81d445e4f1502Douglas Gregor
196677e15ffee2ecc9c1c8f46fd77cab4b5afb59640Douglas Gregor	dev_list_len = r;
197677e15ffee2ecc9c1c8f46fd77cab4b5afb59640Douglas Gregor	for (i = 0; i < dev_list_len; i++) {
198677e15ffee2ecc9c1c8f46fd77cab4b5afb59640Douglas Gregor		libusb_device *dev = dev_list[i];
199677e15ffee2ecc9c1c8f46fd77cab4b5afb59640Douglas Gregor		uint8_t bus_num = libusb_get_bus_number(dev);
2001a49d97d762570027863e9209af81d445e4f1502Douglas Gregor
201677e15ffee2ecc9c1c8f46fd77cab4b5afb59640Douglas Gregor		/* if we already know about it, continue */
202677e15ffee2ecc9c1c8f46fd77cab4b5afb59640Douglas Gregor		if (busses) {
203fa69fc19121da3fc5673ccc00d4e8afa5b540a4fDouglas Gregor			bus = busses;
204fa69fc19121da3fc5673ccc00d4e8afa5b540a4fDouglas Gregor			int found = 0;
205fa69fc19121da3fc5673ccc00d4e8afa5b540a4fDouglas Gregor			do {
2061a49d97d762570027863e9209af81d445e4f1502Douglas Gregor				if (bus_num == bus->location) {
2071a49d97d762570027863e9209af81d445e4f1502Douglas Gregor					found = 1;
2081a49d97d762570027863e9209af81d445e4f1502Douglas Gregor					break;
2091a49d97d762570027863e9209af81d445e4f1502Douglas Gregor				}
2101a49d97d762570027863e9209af81d445e4f1502Douglas Gregor			} while ((bus = bus->next) != NULL);
2111a49d97d762570027863e9209af81d445e4f1502Douglas Gregor			if (found)
2121a49d97d762570027863e9209af81d445e4f1502Douglas Gregor				continue;
2131a49d97d762570027863e9209af81d445e4f1502Douglas Gregor		}
2141a49d97d762570027863e9209af81d445e4f1502Douglas Gregor
2151a49d97d762570027863e9209af81d445e4f1502Douglas Gregor		/* add it to the list of busses */
2161a49d97d762570027863e9209af81d445e4f1502Douglas Gregor		bus = malloc(sizeof(*bus));
2171a49d97d762570027863e9209af81d445e4f1502Douglas Gregor		if (!bus)
2181a49d97d762570027863e9209af81d445e4f1502Douglas Gregor			goto err;
2191a49d97d762570027863e9209af81d445e4f1502Douglas Gregor
2201a49d97d762570027863e9209af81d445e4f1502Douglas Gregor		memset(bus, 0, sizeof(*bus));
2211a49d97d762570027863e9209af81d445e4f1502Douglas Gregor		bus->location = bus_num;
2221a49d97d762570027863e9209af81d445e4f1502Douglas Gregor		sprintf(bus->dirname, "%03d", bus_num);
2231a49d97d762570027863e9209af81d445e4f1502Douglas Gregor		LIST_ADD(busses, bus);
2241a49d97d762570027863e9209af81d445e4f1502Douglas Gregor	}
225677e15ffee2ecc9c1c8f46fd77cab4b5afb59640Douglas Gregor
2261a49d97d762570027863e9209af81d445e4f1502Douglas Gregor	libusb_free_device_list(dev_list, 1);
2271a49d97d762570027863e9209af81d445e4f1502Douglas Gregor	*ret = busses;
2281a49d97d762570027863e9209af81d445e4f1502Douglas Gregor	return 0;
2291a49d97d762570027863e9209af81d445e4f1502Douglas Gregor
2301a49d97d762570027863e9209af81d445e4f1502Douglas Gregorerr:
231677e15ffee2ecc9c1c8f46fd77cab4b5afb59640Douglas Gregor	bus = busses;
232677e15ffee2ecc9c1c8f46fd77cab4b5afb59640Douglas Gregor	while (bus) {
2331a49d97d762570027863e9209af81d445e4f1502Douglas Gregor		struct usb_bus *tbus = bus->next;
2341a49d97d762570027863e9209af81d445e4f1502Douglas Gregor		free(bus);
2351a49d97d762570027863e9209af81d445e4f1502Douglas Gregor		bus = tbus;
2361a49d97d762570027863e9209af81d445e4f1502Douglas Gregor	}
2371a49d97d762570027863e9209af81d445e4f1502Douglas Gregor	return -ENOMEM;
2381a49d97d762570027863e9209af81d445e4f1502Douglas Gregor}
2391a49d97d762570027863e9209af81d445e4f1502Douglas Gregor
2401a49d97d762570027863e9209af81d445e4f1502Douglas GregorAPI_EXPORTED int usb_find_busses(void)
2411a49d97d762570027863e9209af81d445e4f1502Douglas Gregor{
2421a49d97d762570027863e9209af81d445e4f1502Douglas Gregor	struct usb_bus *new_busses = NULL;
2431a49d97d762570027863e9209af81d445e4f1502Douglas Gregor	struct usb_bus *bus;
2441a49d97d762570027863e9209af81d445e4f1502Douglas Gregor	int changes = 0;
2451a49d97d762570027863e9209af81d445e4f1502Douglas Gregor	int r;
2461a49d97d762570027863e9209af81d445e4f1502Douglas Gregor
2471a49d97d762570027863e9209af81d445e4f1502Douglas Gregor	/* libusb-1.0 initialization might have failed, but we can't indicate
2481a49d97d762570027863e9209af81d445e4f1502Douglas Gregor	 * this with libusb-0.1, so trap that situation here */
2491a49d97d762570027863e9209af81d445e4f1502Douglas Gregor	if (!ctx)
250677e15ffee2ecc9c1c8f46fd77cab4b5afb59640Douglas Gregor		return 0;
2511a49d97d762570027863e9209af81d445e4f1502Douglas Gregor
2521a49d97d762570027863e9209af81d445e4f1502Douglas Gregor	usbi_dbg("");
253677e15ffee2ecc9c1c8f46fd77cab4b5afb59640Douglas Gregor	r = find_busses(&new_busses);
254677e15ffee2ecc9c1c8f46fd77cab4b5afb59640Douglas Gregor	if (r < 0) {
2551a49d97d762570027863e9209af81d445e4f1502Douglas Gregor		usbi_err("find_busses failed with error %d", r);
2561a49d97d762570027863e9209af81d445e4f1502Douglas Gregor		return r;
257fa69fc19121da3fc5673ccc00d4e8afa5b540a4fDouglas Gregor	}
258fa69fc19121da3fc5673ccc00d4e8afa5b540a4fDouglas Gregor
2591a49d97d762570027863e9209af81d445e4f1502Douglas Gregor	/* walk through all busses we already know about, removing duplicates
2601a49d97d762570027863e9209af81d445e4f1502Douglas Gregor	 * from the new list. if we do not find it in the new list, the bus
2611a49d97d762570027863e9209af81d445e4f1502Douglas Gregor	 * has been removed. */
2621a49d97d762570027863e9209af81d445e4f1502Douglas Gregor
263677e15ffee2ecc9c1c8f46fd77cab4b5afb59640Douglas Gregor	bus = usb_busses;
264677e15ffee2ecc9c1c8f46fd77cab4b5afb59640Douglas Gregor	while (bus) {
2651a49d97d762570027863e9209af81d445e4f1502Douglas Gregor		struct usb_bus *tbus = bus->next;
266677e15ffee2ecc9c1c8f46fd77cab4b5afb59640Douglas Gregor		struct usb_bus *nbus = new_busses;
267677e15ffee2ecc9c1c8f46fd77cab4b5afb59640Douglas Gregor		int found = 0;
2681a49d97d762570027863e9209af81d445e4f1502Douglas Gregor		usbi_dbg("in loop");
2691a49d97d762570027863e9209af81d445e4f1502Douglas Gregor
2701a49d97d762570027863e9209af81d445e4f1502Douglas Gregor#if 0 /* (yavor)  NO caching */
2711a49d97d762570027863e9209af81d445e4f1502Douglas Gregor		while (nbus) {
272677e15ffee2ecc9c1c8f46fd77cab4b5afb59640Douglas Gregor			struct usb_bus *tnbus = nbus->next;
273677e15ffee2ecc9c1c8f46fd77cab4b5afb59640Douglas Gregor
274677e15ffee2ecc9c1c8f46fd77cab4b5afb59640Douglas Gregor			if (bus->location == nbus->location) {
275fa69fc19121da3fc5673ccc00d4e8afa5b540a4fDouglas Gregor				LIST_DEL(new_busses, nbus);
276677e15ffee2ecc9c1c8f46fd77cab4b5afb59640Douglas Gregor				free(nbus);
277677e15ffee2ecc9c1c8f46fd77cab4b5afb59640Douglas Gregor				found = 1;
2781a49d97d762570027863e9209af81d445e4f1502Douglas Gregor				break;
2791a49d97d762570027863e9209af81d445e4f1502Douglas Gregor			}
280188bdcd1aaf5e9f457cec6851707d7dc3e7bbb15Douglas Gregor			nbus = tnbus;
281188bdcd1aaf5e9f457cec6851707d7dc3e7bbb15Douglas Gregor		}
2821a49d97d762570027863e9209af81d445e4f1502Douglas Gregor#endif
2831a49d97d762570027863e9209af81d445e4f1502Douglas Gregor		if (!found) {
2841a49d97d762570027863e9209af81d445e4f1502Douglas Gregor			/* bus removed */
2851a49d97d762570027863e9209af81d445e4f1502Douglas Gregor			usbi_dbg("bus %d removed", bus->location);
2861a49d97d762570027863e9209af81d445e4f1502Douglas Gregor			changes++;
2871a49d97d762570027863e9209af81d445e4f1502Douglas Gregor			LIST_DEL(usb_busses, bus);
2881a49d97d762570027863e9209af81d445e4f1502Douglas Gregor			free(bus);
2891a49d97d762570027863e9209af81d445e4f1502Douglas Gregor		}
2901a49d97d762570027863e9209af81d445e4f1502Douglas Gregor
2911a49d97d762570027863e9209af81d445e4f1502Douglas Gregor		bus = tbus;
2921a49d97d762570027863e9209af81d445e4f1502Douglas Gregor	}
2931a49d97d762570027863e9209af81d445e4f1502Douglas Gregor
2941a49d97d762570027863e9209af81d445e4f1502Douglas Gregor	/* anything remaining in new_busses is a new bus */
2951a49d97d762570027863e9209af81d445e4f1502Douglas Gregor	bus = new_busses;
2961a49d97d762570027863e9209af81d445e4f1502Douglas Gregor	while (bus) {
2971a49d97d762570027863e9209af81d445e4f1502Douglas Gregor		struct usb_bus *tbus = bus->next;
298fa69fc19121da3fc5673ccc00d4e8afa5b540a4fDouglas Gregor		usbi_dbg("bus %d added", bus->location);
299fa69fc19121da3fc5673ccc00d4e8afa5b540a4fDouglas Gregor		LIST_DEL(new_busses, bus);
3001a49d97d762570027863e9209af81d445e4f1502Douglas Gregor		LIST_ADD(usb_busses, bus);
3011a49d97d762570027863e9209af81d445e4f1502Douglas Gregor		changes++;
3021a49d97d762570027863e9209af81d445e4f1502Douglas Gregor		bus = tbus;
3031a49d97d762570027863e9209af81d445e4f1502Douglas Gregor	}
3041a49d97d762570027863e9209af81d445e4f1502Douglas Gregor
3051a49d97d762570027863e9209af81d445e4f1502Douglas Gregor	return changes;
306fa69fc19121da3fc5673ccc00d4e8afa5b540a4fDouglas Gregor}
307fa69fc19121da3fc5673ccc00d4e8afa5b540a4fDouglas Gregor
308fa69fc19121da3fc5673ccc00d4e8afa5b540a4fDouglas Gregorstatic int find_devices(libusb_device **dev_list, int dev_list_len,
309fa69fc19121da3fc5673ccc00d4e8afa5b540a4fDouglas Gregor	struct usb_bus *bus, struct usb_device **ret)
310fa69fc19121da3fc5673ccc00d4e8afa5b540a4fDouglas Gregor{
311fa69fc19121da3fc5673ccc00d4e8afa5b540a4fDouglas Gregor	struct usb_device *devices = NULL;
312677e15ffee2ecc9c1c8f46fd77cab4b5afb59640Douglas Gregor	struct usb_device *dev;
313677e15ffee2ecc9c1c8f46fd77cab4b5afb59640Douglas Gregor	int i;
314fa69fc19121da3fc5673ccc00d4e8afa5b540a4fDouglas Gregor
315fa69fc19121da3fc5673ccc00d4e8afa5b540a4fDouglas Gregor	for (i = 0; i < dev_list_len; i++) {
316fa69fc19121da3fc5673ccc00d4e8afa5b540a4fDouglas Gregor		libusb_device *newlib_dev = dev_list[i];
317fa69fc19121da3fc5673ccc00d4e8afa5b540a4fDouglas Gregor		uint8_t bus_num = libusb_get_bus_number(newlib_dev);
318fa69fc19121da3fc5673ccc00d4e8afa5b540a4fDouglas Gregor
319fa69fc19121da3fc5673ccc00d4e8afa5b540a4fDouglas Gregor		if (bus_num != bus->location)
320fa69fc19121da3fc5673ccc00d4e8afa5b540a4fDouglas Gregor			continue;
321fa69fc19121da3fc5673ccc00d4e8afa5b540a4fDouglas Gregor
322fa69fc19121da3fc5673ccc00d4e8afa5b540a4fDouglas Gregor		dev = malloc(sizeof(*dev));
323fa69fc19121da3fc5673ccc00d4e8afa5b540a4fDouglas Gregor		if (!dev)
324fa69fc19121da3fc5673ccc00d4e8afa5b540a4fDouglas Gregor			goto err;
325fa69fc19121da3fc5673ccc00d4e8afa5b540a4fDouglas Gregor
326677e15ffee2ecc9c1c8f46fd77cab4b5afb59640Douglas Gregor		/* No need to reference the device now, just take the pointer. We
327677e15ffee2ecc9c1c8f46fd77cab4b5afb59640Douglas Gregor		 * increase the reference count later if we keep the device. */
328fa69fc19121da3fc5673ccc00d4e8afa5b540a4fDouglas Gregor		dev->dev = newlib_dev;
329fa69fc19121da3fc5673ccc00d4e8afa5b540a4fDouglas Gregor
330fa69fc19121da3fc5673ccc00d4e8afa5b540a4fDouglas Gregor		dev->bus = bus;
331677e15ffee2ecc9c1c8f46fd77cab4b5afb59640Douglas Gregor		dev->devnum = libusb_get_device_address(newlib_dev);
332677e15ffee2ecc9c1c8f46fd77cab4b5afb59640Douglas Gregor		sprintf(dev->filename, "%03d", dev->devnum);
3331a49d97d762570027863e9209af81d445e4f1502Douglas Gregor		LIST_ADD(devices, dev);
3341a49d97d762570027863e9209af81d445e4f1502Douglas Gregor	}
3351a49d97d762570027863e9209af81d445e4f1502Douglas Gregor
3361a49d97d762570027863e9209af81d445e4f1502Douglas Gregor	*ret = devices;
3371a49d97d762570027863e9209af81d445e4f1502Douglas Gregor	return 0;
3381a49d97d762570027863e9209af81d445e4f1502Douglas Gregor
3391a49d97d762570027863e9209af81d445e4f1502Douglas Gregorerr:
3401a49d97d762570027863e9209af81d445e4f1502Douglas Gregor	dev = devices;
3411a49d97d762570027863e9209af81d445e4f1502Douglas Gregor	while (dev) {
3421a49d97d762570027863e9209af81d445e4f1502Douglas Gregor		struct usb_device *tdev = dev->next;
3431a49d97d762570027863e9209af81d445e4f1502Douglas Gregor		free(dev);
344a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor		dev = tdev;
345a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor	}
346a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor	return -ENOMEM;
347a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor}
348a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor
349a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregorstatic void clear_endpoint_descriptor(struct usb_endpoint_descriptor *ep)
350a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor{
351a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor	if (ep->extra)
352a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor		free(ep->extra);
353a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor}
354a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor
355a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregorstatic void clear_interface_descriptor(struct usb_interface_descriptor *iface)
356a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor{
357a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor	if (iface->extra)
358a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor		free(iface->extra);
359a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor	if (iface->endpoint) {
360a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor		int i;
361a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor		for (i = 0; i < iface->bNumEndpoints; i++)
362a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor			clear_endpoint_descriptor(iface->endpoint + i);
363a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor		free(iface->endpoint);
364a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor	}
365a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor}
366a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor
367a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregorstatic void clear_interface(struct usb_interface *iface)
368a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor{
369a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor	if (iface->altsetting) {
370a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor		int i;
371a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor		for (i = 0; i < iface->num_altsetting; i++)
372a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor			clear_interface_descriptor(iface->altsetting + i);
373a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor		free(iface->altsetting);
374a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor	}
375a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor}
376a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor
377a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregorstatic void clear_config_descriptor(struct usb_config_descriptor *config)
378a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor{
379a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor	if (config->extra)
380a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor		free(config->extra);
381a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor	if (config->interface) {
382a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor		int i;
383a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor		for (i = 0; i < config->bNumInterfaces; i++)
384a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor			clear_interface(config->interface + i);
385a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor		free(config->interface);
386a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor	}
387a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor}
388a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor
389a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregorstatic void clear_device(struct usb_device *dev)
390a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor{
391a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor	int i;
392a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor	for (i = 0; i < dev->descriptor.bNumConfigurations; i++)
393a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor		clear_config_descriptor(dev->config + i);
394a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor}
395a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor
396a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregorstatic int copy_endpoint_descriptor(struct usb_endpoint_descriptor *dest,
397a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor	const struct libusb_endpoint_descriptor *src)
398a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor{
399a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor	memcpy(dest, src, USB_DT_ENDPOINT_AUDIO_SIZE);
400a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor
401a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor	dest->extralen = src->extra_length;
402a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor	if (src->extra_length) {
403a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor		dest->extra = malloc(src->extra_length);
404a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor		if (!dest->extra)
405a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor			return -ENOMEM;
406a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor		memcpy(dest->extra, src->extra, src->extra_length);
407a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor	}
408a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor
409a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor	return 0;
410a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor}
411a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor
412a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregorstatic int copy_interface_descriptor(struct usb_interface_descriptor *dest,
413a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor	const struct libusb_interface_descriptor *src)
414a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor{
415a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor	int i;
416a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor	int num_endpoints = src->bNumEndpoints;
417a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor	size_t alloc_size = sizeof(struct usb_endpoint_descriptor) * num_endpoints;
418a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor
419a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor	memcpy(dest, src, USB_DT_INTERFACE_SIZE);
420a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor	dest->endpoint = malloc(alloc_size);
421a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor	if (!dest->endpoint)
422a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor		return -ENOMEM;
423a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor	memset(dest->endpoint, 0, alloc_size);
424a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor
425a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor	for (i = 0; i < num_endpoints; i++) {
426a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor		int r = copy_endpoint_descriptor(dest->endpoint + i, &src->endpoint[i]);
427a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor		if (r < 0) {
428a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor			clear_interface_descriptor(dest);
429a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor			return r;
430a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor		}
431a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor	}
432a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor
433a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor	dest->extralen = src->extra_length;
434a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor	if (src->extra_length) {
435a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor		dest->extra = malloc(src->extra_length);
436a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor		if (!dest->extra) {
437a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor			clear_interface_descriptor(dest);
4381a49d97d762570027863e9209af81d445e4f1502Douglas Gregor			return -ENOMEM;
439a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor		}
440a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor		memcpy(dest->extra, src->extra, src->extra_length);
441a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor	}
442a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor
443a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor	return 0;
444a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor}
445a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor
446a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregorstatic int copy_interface(struct usb_interface *dest,
4471a49d97d762570027863e9209af81d445e4f1502Douglas Gregor	const struct libusb_interface *src)
448a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor{
449a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor	int i;
450a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor	int num_altsetting = src->num_altsetting;
451a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor	size_t alloc_size = sizeof(struct usb_interface_descriptor)
452a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor		* num_altsetting;
453a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor
454a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor	dest->num_altsetting = num_altsetting;
455a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor	dest->altsetting = malloc(alloc_size);
456a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor	if (!dest->altsetting)
457a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor		return -ENOMEM;
458a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor	memset(dest->altsetting, 0, alloc_size);
459a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor
460a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor	for (i = 0; i < num_altsetting; i++) {
461a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor		int r = copy_interface_descriptor(dest->altsetting + i,
462a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor			&src->altsetting[i]);
463a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor		if (r < 0) {
464a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor			clear_interface(dest);
465a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor			return r;
466a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor		}
467a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor	}
468a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor
469a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor	return 0;
470a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor}
4718e31d064e7543dde6e4205d5b27a95c96a4c3a4eDouglas Gregor
4728e31d064e7543dde6e4205d5b27a95c96a4c3a4eDouglas Gregorstatic int copy_config_descriptor(struct usb_config_descriptor *dest,
473a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor	const struct libusb_config_descriptor *src)
474a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor{
475a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor	int i;
476a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor	int num_interfaces = src->bNumInterfaces;
477a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor	size_t alloc_size = sizeof(struct usb_interface) * num_interfaces;
478a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor
479a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor	memcpy(dest, src, USB_DT_CONFIG_SIZE);
480a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor	dest->interface = malloc(alloc_size);
481a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor	if (!dest->interface)
482a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor		return -ENOMEM;
483a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor	memset(dest->interface, 0, alloc_size);
484a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor
485a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor	for (i = 0; i < num_interfaces; i++) {
486a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor		int r = copy_interface(dest->interface + i, &src->interface[i]);
487a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor		if (r < 0) {
488a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor			clear_config_descriptor(dest);
489a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor			return r;
490a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor		}
491a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor	}
492a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor
493a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor	dest->extralen = src->extra_length;
494a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor	if (src->extra_length) {
495a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor		dest->extra = malloc(src->extra_length);
496a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor		if (!dest->extra) {
4971a49d97d762570027863e9209af81d445e4f1502Douglas Gregor			clear_config_descriptor(dest);
498a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor			return -ENOMEM;
499a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor		}
5001a49d97d762570027863e9209af81d445e4f1502Douglas Gregor		memcpy(dest->extra, src->extra, src->extra_length);
501a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor	}
502a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor
5031a49d97d762570027863e9209af81d445e4f1502Douglas Gregor	return 0;
5041a49d97d762570027863e9209af81d445e4f1502Douglas Gregor}
505a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor
506a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregorstatic int initialize_device(struct usb_device *dev)
5071a49d97d762570027863e9209af81d445e4f1502Douglas Gregor{
5081a49d97d762570027863e9209af81d445e4f1502Douglas Gregor	libusb_device *newlib_dev = dev->dev;
509a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor	int num_configurations;
510a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor	size_t alloc_size;
511a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor	int r;
512a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor	int i;
513a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor
514a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor	/* device descriptor is identical in both libs */
515a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor	r = libusb_get_device_descriptor(newlib_dev,
516a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor		(struct libusb_device_descriptor *) &dev->descriptor);
5171a49d97d762570027863e9209af81d445e4f1502Douglas Gregor	if (r < 0) {
518a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor		usbi_err("error %d getting device descriptor", r);
519a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor		return compat_err(r);
520a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor	}
521a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor
522a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor	num_configurations = dev->descriptor.bNumConfigurations;
523a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor	alloc_size = sizeof(struct usb_config_descriptor) * num_configurations;
524a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor	dev->config = malloc(alloc_size);
525a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor	if (!dev->config)
5261a49d97d762570027863e9209af81d445e4f1502Douglas Gregor		return -ENOMEM;
527a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor	memset(dev->config, 0, alloc_size);
528a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor
529a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor	/* even though structures are identical, we can't just use libusb-1.0's
530a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor	 * config descriptors because we have to store all configurations in
531a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor	 * a single flat memory area (libusb-1.0 provides separate allocations).
532a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor	 * we hand-copy libusb-1.0's descriptors into our own structures. */
533a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor	for (i = 0; i < num_configurations; i++) {
534a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor		struct libusb_config_descriptor *newlib_config;
535a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor		r = libusb_get_config_descriptor(newlib_dev, i, &newlib_config);
536a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor		if (r < 0) {
537a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor			clear_device(dev);
538a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor			free(dev->config);
539a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor			return compat_err(r);
540a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor		}
5411a49d97d762570027863e9209af81d445e4f1502Douglas Gregor		r = copy_config_descriptor(dev->config + i, newlib_config);
542a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor		libusb_free_config_descriptor(newlib_config);
543a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor		if (r < 0) {
544a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor			clear_device(dev);
545a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor			free(dev->config);
546a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor			return r;
547a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor		}
548a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor	}
549a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor
550a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor	/* libusb doesn't implement this and it doesn't seem that important. If
551a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor	 * someone asks for it, we can implement it in v1.1 or later. */
552a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor	dev->num_children = 0;
553a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor	dev->children = NULL;
554a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor
555a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor	libusb_ref_device(newlib_dev);
556a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor	return 0;
557a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor}
558a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor
559a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregorstatic void free_device(struct usb_device *dev)
560a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor{
561a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor	clear_device(dev);
562a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor	libusb_unref_device(dev->dev);
563677e15ffee2ecc9c1c8f46fd77cab4b5afb59640Douglas Gregor	free(dev);
564677e15ffee2ecc9c1c8f46fd77cab4b5afb59640Douglas Gregor}
565677e15ffee2ecc9c1c8f46fd77cab4b5afb59640Douglas Gregor
566677e15ffee2ecc9c1c8f46fd77cab4b5afb59640Douglas GregorAPI_EXPORTED int usb_find_devices(void)
567a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor{
568a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor	struct usb_bus *bus;
569a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor	libusb_device **dev_list;
570a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor	int dev_list_len;
571a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor	int r;
572a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor	int changes = 0;
573a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor
574ea14a8799f2a6d139491483151cee4341ef1a73eDouglas Gregor	/* libusb-1.0 initialization might have failed, but we can't indicate
575ea14a8799f2a6d139491483151cee4341ef1a73eDouglas Gregor	 * this with libusb-0.1, so trap that situation here */
576ea14a8799f2a6d139491483151cee4341ef1a73eDouglas Gregor	if (!ctx)
577677e15ffee2ecc9c1c8f46fd77cab4b5afb59640Douglas Gregor		return 0;
578677e15ffee2ecc9c1c8f46fd77cab4b5afb59640Douglas Gregor
579677e15ffee2ecc9c1c8f46fd77cab4b5afb59640Douglas Gregor	usbi_dbg("");
580a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor	dev_list_len = libusb_get_device_list(ctx, &dev_list);
581a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor	if (dev_list_len < 0)
582a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor		return compat_err(dev_list_len);
583a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor
584a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor	for (bus = usb_busses; bus; bus = bus->next) {
585a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor		struct usb_device *new_devices = NULL;
586a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor		struct usb_device *dev;
587a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor
588a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor		r = find_devices(dev_list, dev_list_len, bus, &new_devices);
589a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor		if (r < 0) {
590a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor			libusb_free_device_list(dev_list, 1);
591a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor			return r;
592a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor		}
593a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor
594a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor		/* walk through the devices we already know about, removing duplicates
595a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor		 * from the new list. if we do not find it in the new list, the device
596a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor		 * has been removed. */
597a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor		dev = bus->devices;
598a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor		while (dev) {
599a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor			int found = 0;
600a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor			struct usb_device *tdev = dev->next;
601a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor			struct usb_device *ndev = new_devices;
602a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor
603a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor			while (ndev) {
6041a49d97d762570027863e9209af81d445e4f1502Douglas Gregor				if (ndev->devnum == dev->devnum) {
6051a49d97d762570027863e9209af81d445e4f1502Douglas Gregor					LIST_DEL(new_devices, ndev);
606a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor					free(ndev);
607a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor					found = 1;
608a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor					break;
609a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor				}
610a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor				ndev = ndev->next;
611a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor			}
612a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor
613a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor			if (!found) {
614a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor				usbi_dbg("device %d.%d removed",
615a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor					dev->bus->location, dev->devnum);
616a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor				LIST_DEL(bus->devices, dev);
617a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor				free_device(dev);
618a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor				changes++;
619a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor			}
620a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor
621a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor			dev = tdev;
622a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor		}
623a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor
624a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor		/* anything left in new_devices is a new device */
625a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor		dev = new_devices;
626a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor		while (dev) {
627a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor			struct usb_device *tdev = dev->next;
628a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor			r = initialize_device(dev);
629a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor			if (r < 0) {
630a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor				usbi_err("couldn't initialize device %d.%d (error %d)",
631a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor					dev->bus->location, dev->devnum, r);
632a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor				dev = tdev;
633a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor				continue;
634a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor			}
635a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor			usbi_dbg("device %d.%d added", dev->bus->location, dev->devnum);
636a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor			LIST_DEL(new_devices, dev);
637a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor			LIST_ADD(bus->devices, dev);
638a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor			changes++;
639a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor			dev = tdev;
640a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor		}
641a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor	}
642a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor
643a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor	libusb_free_device_list(dev_list, 1);
644a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor	return changes;
645a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor}
646a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor
647a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas GregorAPI_EXPORTED struct usb_bus *usb_get_busses(void)
648a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor{
649a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor	return usb_busses;
650a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor}
651a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor
652a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas GregorAPI_EXPORTED usb_dev_handle *usb_open(struct usb_device *dev)
653a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor{
654a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor	int r;
655a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor	usbi_dbg("");
656a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor
657a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor	usb_dev_handle *udev = malloc(sizeof(*udev));
658a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor	if (!udev)
659a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor		return NULL;
660a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor
661a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor	r = libusb_open((libusb_device *) dev->dev, &udev->handle);
662a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor	if (r < 0) {
663a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor		usbi_err("could not open device, error %d", r);
664a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor		free(udev);
665a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor		errno = libusb_to_errno(r);
666a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor		return NULL;
667a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor	}
668a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor
669a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor	udev->last_claimed_interface = -1;
6701a49d97d762570027863e9209af81d445e4f1502Douglas Gregor	udev->device = dev;
671a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor	return udev;
672a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor}
673a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor
674a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas GregorAPI_EXPORTED int usb_close(usb_dev_handle *dev)
675a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor{
676a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor	usbi_dbg("");
677a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor	libusb_close(dev->handle);
678a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor	free(dev);
679a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor	return 0;
680a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor}
681a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor
682a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas GregorAPI_EXPORTED struct usb_device *usb_device(usb_dev_handle *dev)
683a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor{
684a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor	return dev->device;
685a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor}
686a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor
687a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas GregorAPI_EXPORTED int usb_set_configuration(usb_dev_handle *dev, int configuration)
688a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor{
689a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor	usbi_dbg("configuration %d", configuration);
690a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor	return compat_err(libusb_set_configuration(dev->handle, configuration));
691a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor}
692a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor
693a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas GregorAPI_EXPORTED int usb_claim_interface(usb_dev_handle *dev, int interface)
694a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor{
695a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor	int r;
696a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor	usbi_dbg("interface %d", interface);
697a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor
698a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor	r = libusb_claim_interface(dev->handle, interface);
699a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor	if (r == 0) {
700a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor		dev->last_claimed_interface = interface;
701a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor		return 0;
702a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor	}
703a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor
704a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor	return compat_err(r);
705a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor}
706a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor
707a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas GregorAPI_EXPORTED int usb_release_interface(usb_dev_handle *dev, int interface)
708a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor{
709a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor	int r;
710a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor	usbi_dbg("interface %d", interface);
711a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor
712a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor	r = libusb_release_interface(dev->handle, interface);
713a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor	if (r == 0)
714a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor		dev->last_claimed_interface = -1;
715a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor
716a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor	return compat_err(r);
717a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor}
718a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor
719a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas GregorAPI_EXPORTED int usb_set_altinterface(usb_dev_handle *dev, int alternate)
720a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor{
721a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor	usbi_dbg("alternate %d", alternate);
722a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor	if (dev->last_claimed_interface < 0)
723a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor		return -(errno=EINVAL);
724a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor
725a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor	return compat_err(libusb_set_interface_alt_setting(dev->handle,
726a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor		dev->last_claimed_interface, alternate));
727a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor}
728a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor
729a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas GregorAPI_EXPORTED int usb_resetep(usb_dev_handle *dev, unsigned int ep)
730a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor{
731a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor	return compat_err(usb_clear_halt(dev, ep));
732a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor}
733a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor
734a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas GregorAPI_EXPORTED int usb_clear_halt(usb_dev_handle *dev, unsigned int ep)
735a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor{
736a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor	usbi_dbg("endpoint %x", ep);
737a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor	return compat_err(libusb_clear_halt(dev->handle, ep & 0xff));
738a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor}
739a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor
740a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas GregorAPI_EXPORTED int usb_reset(usb_dev_handle *dev)
741a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor{
742a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor	usbi_dbg("");
743a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor	return compat_err(libusb_reset_device(dev->handle));
744a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor}
745a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor
746a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregorstatic int usb_bulk_io(usb_dev_handle *dev, int ep, char *bytes,
747a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor	int size, int timeout)
748a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor{
749a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor	int actual_length;
750a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor	int r;
751a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor	usbi_dbg("endpoint %x size %d timeout %d", ep, size, timeout);
752a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor	r = libusb_bulk_transfer(dev->handle, ep & 0xff, bytes, size,
753a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor		&actual_length, timeout);
754a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor
755a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor	/* if we timed out but did transfer some data, report as successful short
756a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor	 * read. FIXME: is this how libusb-0.1 works? */
757a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor	if (r == 0 || (r == LIBUSB_ERROR_TIMEOUT && actual_length > 0))
758a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor		return actual_length;
759a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor
760a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor	return compat_err(r);
761a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor}
762a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor
763a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas GregorAPI_EXPORTED int usb_bulk_read(usb_dev_handle *dev, int ep, char *bytes,
764a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor	int size, int timeout)
765a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor{
766a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor	if (!(ep & USB_ENDPOINT_IN)) {
767a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor		/* libusb-0.1 will strangely fix up a read request from endpoint
768a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor		 * 0x01 to be from endpoint 0x81. do the same thing here, but
769a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor		 * warn about this silly behaviour. */
770a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor		usbi_warn("endpoint %x is missing IN direction bit, fixing");
771a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor		ep |= USB_ENDPOINT_IN;
772a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor	}
773a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor
774a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor	return usb_bulk_io(dev, ep, bytes, size, timeout);
775a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor}
776a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor
777a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas GregorAPI_EXPORTED int usb_bulk_write(usb_dev_handle *dev, int ep, char *bytes,
778a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor	int size, int timeout)
779a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor{
780a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor	if (ep & USB_ENDPOINT_IN) {
781a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor		/* libusb-0.1 on BSD strangely fix up a write request to endpoint
782a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor		 * 0x81 to be to endpoint 0x01. do the same thing here, but
783a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor		 * warn about this silly behaviour. */
784a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor		usbi_warn("endpoint %x has excessive IN direction bit, fixing");
785a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor		ep &= ~USB_ENDPOINT_IN;
786a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor	}
787a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor
788a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor	return usb_bulk_io(dev, ep, bytes, size, timeout);
789a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor}
790a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor
791a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregorstatic int usb_interrupt_io(usb_dev_handle *dev, int ep, char *bytes,
792a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor	int size, int timeout)
79370e7aeccbf5856a84f81366c6c1a0c0c01e70063Rafael Espindola{
79470e7aeccbf5856a84f81366c6c1a0c0c01e70063Rafael Espindola	int actual_length;
795a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor	int r;
796a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor	usbi_dbg("endpoint %x size %d timeout %d", ep, size, timeout);
797a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor	r = libusb_interrupt_transfer(dev->handle, ep & 0xff, bytes, size,
798d2db16f59601bc028f4f973990cc6d4abe95b91aNAKAMURA Takumi		&actual_length, timeout);
799a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor
800a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor	/* if we timed out but did transfer some data, report as successful short
801a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor	 * read. FIXME: is this how libusb-0.1 works? */
802a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor	if (r == 0 || (r == LIBUSB_ERROR_TIMEOUT && actual_length > 0))
803a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor		return actual_length;
804a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor
805a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor	return compat_err(r);
806a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor}
807a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor
808a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas GregorAPI_EXPORTED int usb_interrupt_read(usb_dev_handle *dev, int ep, char *bytes,
809a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor	int size, int timeout)
810a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor{
811a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor	if (!(ep & USB_ENDPOINT_IN)) {
812a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor		/* libusb-0.1 will strangely fix up a read request from endpoint
813a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor		 * 0x01 to be from endpoint 0x81. do the same thing here, but
814a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor		 * warn about this silly behaviour. */
815a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor		usbi_warn("endpoint %x is missing IN direction bit, fixing");
816a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor		ep |= USB_ENDPOINT_IN;
817a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor	}
818a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor	return usb_interrupt_io(dev, ep, bytes, size, timeout);
819a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor}
820a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas Gregor
821a6b00fc97669aa25d89ae9f202b05dfadfd0e324Douglas GregorAPI_EXPORTED int usb_interrupt_write(usb_dev_handle *dev, int ep, char *bytes,
82287f9d81d0ab806dcf6ca50a0c068dcb2ba7f51b3Argyrios Kyrtzidis	int size, int timeout)
82387f9d81d0ab806dcf6ca50a0c068dcb2ba7f51b3Argyrios Kyrtzidis{
82487f9d81d0ab806dcf6ca50a0c068dcb2ba7f51b3Argyrios Kyrtzidis	if (ep & USB_ENDPOINT_IN) {
82587f9d81d0ab806dcf6ca50a0c068dcb2ba7f51b3Argyrios Kyrtzidis		/* libusb-0.1 on BSD strangely fix up a write request to endpoint
82687f9d81d0ab806dcf6ca50a0c068dcb2ba7f51b3Argyrios Kyrtzidis		 * 0x81 to be to endpoint 0x01. do the same thing here, but
82787f9d81d0ab806dcf6ca50a0c068dcb2ba7f51b3Argyrios Kyrtzidis		 * warn about this silly behaviour. */
82887f9d81d0ab806dcf6ca50a0c068dcb2ba7f51b3Argyrios Kyrtzidis		usbi_warn("endpoint %x has excessive IN direction bit, fixing");
82987f9d81d0ab806dcf6ca50a0c068dcb2ba7f51b3Argyrios Kyrtzidis		ep &= ~USB_ENDPOINT_IN;
83087f9d81d0ab806dcf6ca50a0c068dcb2ba7f51b3Argyrios Kyrtzidis	}
83187f9d81d0ab806dcf6ca50a0c068dcb2ba7f51b3Argyrios Kyrtzidis
83287f9d81d0ab806dcf6ca50a0c068dcb2ba7f51b3Argyrios Kyrtzidis	return usb_interrupt_io(dev, ep, bytes, size, timeout);
83387f9d81d0ab806dcf6ca50a0c068dcb2ba7f51b3Argyrios Kyrtzidis}
83487f9d81d0ab806dcf6ca50a0c068dcb2ba7f51b3Argyrios Kyrtzidis
83587f9d81d0ab806dcf6ca50a0c068dcb2ba7f51b3Argyrios KyrtzidisAPI_EXPORTED int usb_control_msg(usb_dev_handle *dev, int bmRequestType,
83687f9d81d0ab806dcf6ca50a0c068dcb2ba7f51b3Argyrios Kyrtzidis	int bRequest, int wValue, int wIndex, char *bytes, int size, int timeout)
83787f9d81d0ab806dcf6ca50a0c068dcb2ba7f51b3Argyrios Kyrtzidis{
83887f9d81d0ab806dcf6ca50a0c068dcb2ba7f51b3Argyrios Kyrtzidis	int r;
83987f9d81d0ab806dcf6ca50a0c068dcb2ba7f51b3Argyrios Kyrtzidis	usbi_dbg("RQT=%x RQ=%x V=%x I=%x len=%d timeout=%d", bmRequestType,
84087f9d81d0ab806dcf6ca50a0c068dcb2ba7f51b3Argyrios Kyrtzidis		bRequest, wValue, wIndex, size, timeout);
84187f9d81d0ab806dcf6ca50a0c068dcb2ba7f51b3Argyrios Kyrtzidis
84287f9d81d0ab806dcf6ca50a0c068dcb2ba7f51b3Argyrios Kyrtzidis	r = libusb_control_transfer(dev->handle, bmRequestType & 0xff,
84387f9d81d0ab806dcf6ca50a0c068dcb2ba7f51b3Argyrios Kyrtzidis		bRequest & 0xff, wValue & 0xffff, wIndex & 0xffff, bytes, size & 0xffff,
84487f9d81d0ab806dcf6ca50a0c068dcb2ba7f51b3Argyrios Kyrtzidis		timeout);
84587f9d81d0ab806dcf6ca50a0c068dcb2ba7f51b3Argyrios Kyrtzidis
84687f9d81d0ab806dcf6ca50a0c068dcb2ba7f51b3Argyrios Kyrtzidis	if (r >= 0)
84787f9d81d0ab806dcf6ca50a0c068dcb2ba7f51b3Argyrios Kyrtzidis		return r;
84887f9d81d0ab806dcf6ca50a0c068dcb2ba7f51b3Argyrios Kyrtzidis
84987f9d81d0ab806dcf6ca50a0c068dcb2ba7f51b3Argyrios Kyrtzidis	return compat_err(r);
85087f9d81d0ab806dcf6ca50a0c068dcb2ba7f51b3Argyrios Kyrtzidis}
85187f9d81d0ab806dcf6ca50a0c068dcb2ba7f51b3Argyrios Kyrtzidis
85287f9d81d0ab806dcf6ca50a0c068dcb2ba7f51b3Argyrios KyrtzidisAPI_EXPORTED int usb_get_string(usb_dev_handle *dev, int desc_index, int langid,
853	char *buf, size_t buflen)
854{
855	int r;
856	r = libusb_get_string_descriptor(dev->handle, desc_index & 0xff,
857		langid & 0xffff, buf, (int) buflen);
858	if (r >= 0)
859		return r;
860	return compat_err(r);
861}
862
863API_EXPORTED int usb_get_string_simple(usb_dev_handle *dev, int desc_index,
864	char *buf, size_t buflen)
865{
866	int r;
867	r = libusb_get_string_descriptor_ascii(dev->handle, desc_index & 0xff,
868		buf, (int) buflen);
869	if (r >= 0)
870		return r;
871	return compat_err(r);
872}
873
874API_EXPORTED int usb_get_descriptor(usb_dev_handle *dev, unsigned char type,
875	unsigned char desc_index, void *buf, int size)
876{
877	int r;
878	r = libusb_get_descriptor(dev->handle, type, desc_index, buf, size);
879	if (r >= 0)
880		return r;
881	return compat_err(r);
882}
883
884API_EXPORTED int usb_get_descriptor_by_endpoint(usb_dev_handle *dev, int ep,
885	unsigned char type, unsigned char desc_index, void *buf, int size)
886{
887	/* this function doesn't make much sense - the specs don't talk about
888	 * getting a descriptor "by endpoint". libusb-1.0 does not provide this
889	 * functionality so we just send a control message directly */
890	int r;
891	r = libusb_control_transfer(dev->handle,
892		LIBUSB_ENDPOINT_IN | (ep & 0xff), LIBUSB_REQUEST_GET_DESCRIPTOR,
893		(type << 8) | desc_index, 0, buf, size, 1000);
894	if (r >= 0)
895		return r;
896	return compat_err(r);
897}
898
899API_EXPORTED int usb_get_driver_np(usb_dev_handle *dev, int interface,
900	char *name, unsigned int namelen)
901{
902	int r = libusb_kernel_driver_active(dev->handle, interface);
903	if (r == 1) {
904		/* libusb-1.0 doesn't expose driver name, so fill in a dummy value */
905		snprintf(name, namelen, "dummy");
906		return 0;
907	} else if (r == 0) {
908		return -(errno=ENODATA);
909	} else {
910		return compat_err(r);
911	}
912}
913
914API_EXPORTED int usb_detach_kernel_driver_np(usb_dev_handle *dev, int interface)
915{
916	return compat_err(libusb_detach_kernel_driver(dev->handle, interface));
917}
918
919