blob: 4182584f14830cb419815cfdf45b449772d68446 [file] [log] [blame]
Yavor Goulisheve9a68312011-05-23 11:58:06 -07001/*
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