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