summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorpancake <pancake@dazo>2007-06-12 15:29:07 +0200
committerpancake <pancake@dazo>2007-06-12 15:29:07 +0200
commitea97ac427eb9ff7ec48baf3a5ab7cc293fc34b70 (patch)
tree271288556a4a431a25746e5da596feb3dd580d64
parenta3af55acb4141cd0d23f53b2ec0c5c1d2434aa22 (diff)
download0xFFFF-ea97ac427eb9ff7ec48baf3a5ab7cc293fc34b70.tar.bz2
* Initial import of the libusb source tree into the flasher - optional, but useful for embedding - avoids gnu autosux problems
-rw-r--r--libusb/Makefile8
-rw-r--r--libusb/bsd.c637
-rw-r--r--libusb/config.h98
-rw-r--r--libusb/darwin.c1209
-rw-r--r--libusb/descriptors.c520
-rw-r--r--libusb/error.c36
-rw-r--r--libusb/error.h31
-rw-r--r--libusb/linux.c733
-rw-r--r--libusb/linux.h119
-rw-r--r--libusb/usb.c307
-rw-r--r--libusb/usb.h337
-rw-r--r--libusb/usbi.h74
-rw-r--r--libusb/usbpp.h855
13 files changed, 4964 insertions, 0 deletions
diff --git a/libusb/Makefile b/libusb/Makefile
new file mode 100644
index 0000000..a6a60fc
--- /dev/null
+++ b/libusb/Makefile
@@ -0,0 +1,8 @@
+#include ../config.mk
+OBJ=linux.o usb.o descriptors.o error.o
+
+all: ${OBJ}
+ ${CC} ${CFLAGS} ${LDFLAGS} -fPIC -I . ${OBJ} -shared -o libusb.so
+
+clean:
+ -rm -f libusb.so ${OBJ}
diff --git a/libusb/bsd.c b/libusb/bsd.c
new file mode 100644
index 0000000..e634867
--- /dev/null
+++ b/libusb/bsd.c
@@ -0,0 +1,637 @@
+/*
+ * (Free|Open|Net)BSD USB support
+ *
+ * Derived from Linux version by Richard Tobin.
+ *
+ * $Id: bsd.c,v 1.33 2006/03/04 01:16:10 jerdfelt Exp $
+ * $Name: $
+ *
+ * This library is covered by the LGPL, read LICENSE for details.
+ */
+
+/*
+ * Note: I don't have a clue what I'm doing. I just looked at the
+ * man pages and source to try and find things that did the same as
+ * the Linux version. -- Richard
+ *
+ * johnjen@reynoldsnet.org - minor fixes with debug mode output. Consistent brace
+ * use as well as indenting. More error messages put in to test for failure
+ * modes with /dev/ permissions (when it happens). Note: I, like Richard, have
+ * no clue what I'm doing. Patches to increase/fix functionality happily
+ * accepted!
+ */
+
+/* dirkx@webweaving.org - minor changes to make things actually work
+ * for both read and write.
+ */
+
+#if defined(__FreeBSD__) && !defined(__FreeBSD_kernel__)
+#define __FreeBSD_kernel__ __FreeBSD__
+#endif
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <assert.h>
+#include <sys/time.h>
+#include <sys/ioctl.h>
+
+#include <dev/usb/usb.h>
+
+#include "usbi.h"
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#ifdef HAVE_OLD_DEV_USB_USB_H
+/*
+ * It appears some of the BSD's (OpenBSD atleast) have switched over to a
+ * new naming convention, so we setup some macro's for backward
+ * compability with older versions --jerdfelt
+ */
+
+/* struct usb_ctl_request */
+#define ucr_addr addr
+#define ucr_request request
+#define ucr_data data
+#define ucr_flags flags
+#define ucr_actlen actlen
+
+/* struct usb_alt_interface */
+#define uai_config_index config_index
+#define uai_interface_index interface_index
+#define uai_alt_no alt_no
+
+/* struct usb_config_desc */
+#define ucd_config_index config_index
+#define ucd_desc desc
+
+/* struct usb_interface_desc */
+#define uid_config_index config_index
+#define uid_interface_index interface_index
+#define uid_alt_index alt_index
+#define uid_desc desc
+
+/* struct usb_endpoint_desc */
+#define ued_config_index config_index
+#define ued_interface_index interface_index
+#define ued_alt_index alt_index
+#define ued_endpoint_index endpoint_index
+#define ued_desc desc
+
+/* struct usb_full_desc */
+#define ufd_config_index config_index
+#define ufd_size size
+#define ufd_data data
+
+/* struct usb_string_desc */
+#define usd_string_index string_index
+#define usd_language_id language_id
+#define usd_desc desc
+
+/* struct usb_ctl_report_desc */
+#define ucrd_size size
+#define ucrd_data data
+
+/* struct usb_device_info */
+#define udi_bus bus
+#define udi_addr addr
+#define udi_cookie cookie
+#define udi_product product
+#define udi_vendor vendor
+#define udi_release release
+#define udi_productNo productNo
+#define udi_vendorNo vendorNo
+#define udi_releaseNo releaseNo
+#define udi_class class
+#define udi_subclass subclass
+#define udi_protocol protocol
+#define udi_config config
+#define udi_lowspeed lowspeed
+#define udi_power power
+#define udi_nports nports
+#define udi_devnames devnames
+#define udi_ports ports
+
+/* struct usb_ctl_report */
+#define ucr_report report
+#define ucr_data data
+
+/* struct usb_device_stats */
+#define uds_requests requests
+#endif
+
+static int ensure_ep_open(usb_dev_handle *dev, int ep, int mode);
+
+#define MAX_CONTROLLERS 10
+
+/* This records the file descriptors for the endpoints. It doesn't seem
+ to work to re-open them for each read (as well as being inefficient). */
+
+struct bsd_usb_dev_handle_info {
+ int ep_fd[USB_MAX_ENDPOINTS];
+};
+
+int usb_os_open(usb_dev_handle *dev)
+{
+ int i;
+ struct bsd_usb_dev_handle_info *info;
+ char ctlpath[PATH_MAX + 1];
+
+ info = malloc(sizeof(struct bsd_usb_dev_handle_info));
+ if (!info)
+ USB_ERROR(-ENOMEM);
+ dev->impl_info = info;
+
+#ifdef __FreeBSD_kernel__
+ snprintf(ctlpath, PATH_MAX, "%s", dev->device->filename);
+#else
+ snprintf(ctlpath, PATH_MAX, "%s.00", dev->device->filename);
+#endif
+ dev->fd = open(ctlpath, O_RDWR);
+ if (dev->fd < 0) {
+ dev->fd = open(ctlpath, O_RDONLY);
+ if (dev->fd < 0) {
+ free(info);
+ USB_ERROR_STR(-errno, "failed to open %s: %s",
+ ctlpath, strerror(errno));
+ }
+ }
+
+ /* Mark the endpoints as not yet open */
+ for (i = 0; i < USB_MAX_ENDPOINTS; i++)
+ info->ep_fd[i] = -1;
+
+ return 0;
+}
+
+int usb_os_close(usb_dev_handle *dev)
+{
+ struct bsd_usb_dev_handle_info *info = dev->impl_info;
+ int i;
+
+ /* Close any open endpoints */
+
+ for (i = 0; i < USB_MAX_ENDPOINTS; i++)
+ if (info->ep_fd[i] >= 0) {
+ if (usb_debug >= 2)
+ fprintf(stderr, "usb_os_close: closing endpoint %d\n", info->ep_fd[i]);
+ close(info->ep_fd[i]);
+ }
+
+ free(info);
+
+ if (dev->fd <= 0)
+ return 0;
+
+ if (close(dev->fd) == -1)
+ /* Failing trying to close a file really isn't an error, so return 0 */
+ USB_ERROR_STR(0, "tried to close device fd %d: %s", dev->fd,
+ strerror(errno));
+
+ return 0;
+}
+
+int usb_set_configuration(usb_dev_handle *dev, int configuration)
+{
+ int ret;
+
+ ret = ioctl(dev->fd, USB_SET_CONFIG, &configuration);
+ if (ret < 0)
+ USB_ERROR_STR(-errno, "could not set config %d: %s", configuration,
+ strerror(errno));
+
+ dev->config = configuration;
+
+ return 0;
+}
+
+int usb_claim_interface(usb_dev_handle *dev, int interface)
+{
+ /* BSD doesn't have the corresponding ioctl. It seems to
+ be sufficient to open the relevant endpoints as needed. */
+
+ dev->interface = interface;
+
+ return 0;
+}
+
+int usb_release_interface(usb_dev_handle *dev, int interface)
+{
+ /* See above */
+ return 0;
+}
+
+int usb_set_altinterface(usb_dev_handle *dev, int alternate)
+{
+ int ret;
+ struct usb_alt_interface intf;
+
+ if (dev->interface < 0)
+ USB_ERROR(-EINVAL);
+
+ intf.uai_interface_index = dev->interface;
+ intf.uai_alt_no = alternate;
+
+ ret = ioctl(dev->fd, USB_SET_ALTINTERFACE, &intf);
+ if (ret < 0)
+ USB_ERROR_STR(-errno, "could not set alt intf %d/%d: %s",
+ dev->interface, alternate, strerror(errno));
+
+ dev->altsetting = alternate;
+
+ return 0;
+}
+
+static int ensure_ep_open(usb_dev_handle *dev, int ep, int mode)
+{
+ struct bsd_usb_dev_handle_info *info = dev->impl_info;
+ int fd;
+ char buf[20];
+
+ /* Get the address for this endpoint; we could check
+ * the mode against the direction; but we've done that
+ * already in the usb_bulk_read/write.
+ */
+ ep = UE_GET_ADDR(ep);
+
+ if (info->ep_fd[ep] < 0) {
+#ifdef __FreeBSD_kernel__
+ snprintf(buf, sizeof(buf) - 1, "%s.%d", dev->device->filename, ep);
+#else
+ snprintf(buf, sizeof(buf) - 1, "%s.%02d", dev->device->filename, ep);
+#endif
+ /* Try to open it O_RDWR first for those devices which have in and out
+ * endpoints with the same address (eg 0x02 and 0x82)
+ */
+ fd = open(buf, O_RDWR);
+ if (fd < 0 && errno == ENXIO)
+ fd = open(buf, mode);
+ if (fd < 0)
+ USB_ERROR_STR(-errno, "can't open %s for bulk read: %s",
+ buf, strerror(errno));
+ info->ep_fd[ep] = fd;
+ }
+
+ return info->ep_fd[ep];
+}
+
+int usb_bulk_write(usb_dev_handle *dev, int ep, char *bytes, int size,
+ int timeout)
+{
+ int fd, ret;
+
+ /* Ensure the endpoint address is correct */
+ ep &= ~USB_ENDPOINT_IN;
+
+ fd = ensure_ep_open(dev, ep, O_WRONLY);
+ if (fd < 0) {
+ if (usb_debug >= 2) {
+#ifdef __FreeBSD_kernel__
+ fprintf (stderr, "usb_bulk_write: got negative open file descriptor for endpoint %d\n", UE_GET_ADDR(ep));
+#else
+ fprintf (stderr, "usb_bulk_write: got negative open file descriptor for endpoint %02d\n", UE_GET_ADDR(ep));
+#endif
+ }
+ return fd;
+ }
+
+ ret = ioctl(fd, USB_SET_TIMEOUT, &timeout);
+ if (ret < 0)
+ USB_ERROR_STR(-errno, "error setting timeout: %s",
+ strerror(errno));
+
+ ret = write(fd, bytes, size);
+ if (ret < 0)
+#ifdef __FreeBSD_kernel__
+ USB_ERROR_STR(-errno, "error writing to bulk endpoint %s.%d: %s",
+ dev->device->filename, UE_GET_ADDR(ep), strerror(errno));
+#else
+ USB_ERROR_STR(-errno, "error writing to bulk endpoint %s.%02d: %s",
+ dev->device->filename, UE_GET_ADDR(ep), strerror(errno));
+#endif
+
+ return size;
+}
+
+int usb_bulk_read(usb_dev_handle *dev, int ep, char *bytes, int size,
+ int timeout)
+{
+ int fd, ret, one = 1;
+
+ /* Ensure the endpoint address is correct */
+ ep |= USB_ENDPOINT_IN;
+
+ fd = ensure_ep_open(dev, ep, O_RDONLY);
+ if (fd < 0) {
+ if (usb_debug >= 2) {
+#ifdef __FreeBSD_kernel__
+ fprintf (stderr, "usb_bulk_read: got negative open file descriptor for endpoint %d\n", UE_GET_ADDR(ep));
+#else
+ fprintf (stderr, "usb_bulk_read: got negative open file descriptor for endpoint %02d\n", UE_GET_ADDR(ep));
+#endif
+ }
+ return fd;
+ }
+
+ ret = ioctl(fd, USB_SET_TIMEOUT, &timeout);
+ if (ret < 0)
+ USB_ERROR_STR(-errno, "error setting timeout: %s", strerror(errno));
+
+ ret = ioctl(fd, USB_SET_SHORT_XFER, &one);
+ if (ret < 0)
+ USB_ERROR_STR(-errno, "error setting short xfer: %s", strerror(errno));
+
+ ret = read(fd, bytes, size);
+ if (ret < 0)
+#ifdef __FreeBSD_kernel__
+ USB_ERROR_STR(-errno, "error reading from bulk endpoint %s.%d: %s",
+ dev->device->filename, UE_GET_ADDR(ep), strerror(errno));
+#else
+ USB_ERROR_STR(-errno, "error reading from bulk endpoint %s.%02d: %s",
+ dev->device->filename, UE_GET_ADDR(ep), strerror(errno));
+#endif
+
+ return ret;
+}
+
+int usb_interrupt_write(usb_dev_handle *dev, int ep, char *bytes, int size,
+ int timeout)
+{
+ int fd, ret, sent = 0;
+
+ /* Ensure the endpoint address is correct */
+ ep &= ~USB_ENDPOINT_IN;
+
+ fd = ensure_ep_open(dev, ep, O_WRONLY);
+ if (fd < 0) {
+ if (usb_debug >= 2) {
+#ifdef __FreeBSD_kernel__
+ fprintf (stderr, "usb_interrupt_write: got negative open file descriptor for endpoint %d\n", UE_GET_ADDR(ep));
+#else
+ fprintf (stderr, "usb_interrupt_write: got negative open file descriptor for endpoint %02d\n", UE_GET_ADDR(ep));
+#endif
+ }
+ return fd;
+ }
+
+ ret = ioctl(fd, USB_SET_TIMEOUT, &timeout);
+ if (ret < 0)
+ USB_ERROR_STR(-errno, "error setting timeout: %s",
+ strerror(errno));
+
+ do {
+ ret = write(fd, bytes+sent, size-sent);
+ if (ret < 0)
+#ifdef __FreeBSD_kernel__
+ USB_ERROR_STR(-errno, "error writing to interrupt endpoint %s.%d: %s",
+ dev->device->filename, UE_GET_ADDR(ep), strerror(errno));
+#else
+ USB_ERROR_STR(-errno, "error writing to interrupt endpoint %s.%02d: %s",
+ dev->device->filename, UE_GET_ADDR(ep), strerror(errno));
+#endif
+
+ sent += ret;
+ } while (ret > 0 && sent < size);
+
+ return sent;
+}
+
+int usb_interrupt_read(usb_dev_handle *dev, int ep, char *bytes, int size,
+ int timeout)
+{
+ int fd, ret, retrieved = 0, one = 1;
+
+ /* Ensure the endpoint address is correct */
+ ep |= USB_ENDPOINT_IN;
+
+ fd = ensure_ep_open(dev, ep, O_RDONLY);
+ if (fd < 0) {
+ if (usb_debug >= 2) {
+#ifdef __FreeBSD_kernel__
+ fprintf (stderr, "usb_interrupt_read: got negative open file descriptor for endpoint %d\n", UE_GET_ADDR(ep));
+#else
+ fprintf (stderr, "usb_interrupt_read: got negative open file descriptor for endpoint %02d\n", UE_GET_ADDR(ep));
+#endif
+ }
+ return fd;
+ }
+
+ ret = ioctl(fd, USB_SET_TIMEOUT, &timeout);
+ if (ret < 0)
+ USB_ERROR_STR(-errno, "error setting timeout: %s", strerror(errno));
+
+ ret = ioctl(fd, USB_SET_SHORT_XFER, &one);
+ if (ret < 0)
+ USB_ERROR_STR(-errno, "error setting short xfer: %s", strerror(errno));
+
+ do {
+ ret = read(fd, bytes+retrieved, size-retrieved);
+ if (ret < 0)
+#ifdef __FreeBSD_kernel__
+ USB_ERROR_STR(-errno, "error reading from interrupt endpoint %s.%d: %s",
+ dev->device->filename, UE_GET_ADDR(ep), strerror(errno));
+#else
+ USB_ERROR_STR(-errno, "error reading from interrupt endpoint %s.%02d: %s",
+ dev->device->filename, UE_GET_ADDR(ep), strerror(errno));
+#endif
+ retrieved += ret;
+ } while (ret > 0 && retrieved < size);
+
+ return retrieved;
+}
+
+int usb_control_msg(usb_dev_handle *dev, int requesttype, int request,
+ int value, int index, char *bytes, int size, int timeout)
+{
+ struct usb_ctl_request req;
+ int ret;
+
+ if (usb_debug >= 3)
+ fprintf(stderr, "usb_control_msg: %d %d %d %d %p %d %d\n",
+ requesttype, request, value, index, bytes, size, timeout);
+
+ req.ucr_request.bmRequestType = requesttype;
+ req.ucr_request.bRequest = request;
+ USETW(req.ucr_request.wValue, value);
+ USETW(req.ucr_request.wIndex, index);
+ USETW(req.ucr_request.wLength, size);
+
+ req.ucr_data = bytes;
+ req.ucr_flags = USBD_SHORT_XFER_OK;
+
+ ret = ioctl(dev->fd, USB_SET_TIMEOUT, &timeout);
+#if (__NetBSD__ || __OpenBSD__)
+ if (ret < 0 && errno != EINVAL)
+#else
+ if (ret < 0)
+#endif
+ USB_ERROR_STR(-errno, "error setting timeout: %s",
+ strerror(errno));
+
+ ret = ioctl(dev->fd, USB_DO_REQUEST, &req);
+ if (ret < 0)
+ USB_ERROR_STR(-errno, "error sending control message: %s",
+ strerror(errno));
+
+ return UGETW(req.ucr_request.wLength);
+}
+
+int usb_os_find_busses(struct usb_bus **busses)
+{
+ struct usb_bus *fbus = NULL;
+ int controller;
+ int fd;
+ char buf[20];
+
+ for (controller = 0; controller < MAX_CONTROLLERS; controller++) {
+ struct usb_bus *bus;
+
+ snprintf(buf, sizeof(buf) - 1, "/dev/usb%d", controller);
+ fd = open(buf, O_RDWR);
+ if (fd < 0) {
+ if (usb_debug >= 2)
+ if (errno != ENXIO && errno != ENOENT)
+ fprintf(stderr, "usb_os_find_busses: can't open %s: %s\n",
+ buf, strerror(errno));
+ continue;
+ }
+ close(fd);
+
+ bus = malloc(sizeof(*bus));
+ if (!bus)
+ USB_ERROR(-ENOMEM);
+
+ memset((void *)bus, 0, sizeof(*bus));
+
+ strncpy(bus->dirname, buf, sizeof(bus->dirname) - 1);
+ bus->dirname[sizeof(bus->dirname) - 1] = 0;
+
+ LIST_ADD(fbus, bus);
+
+ if (usb_debug >= 2)
+ fprintf(stderr, "usb_os_find_busses: Found %s\n", bus->dirname);
+ }
+
+ *busses = fbus;
+
+ return 0;
+}
+
+int usb_os_find_devices(struct usb_bus *bus, struct usb_device **devices)
+{
+ struct usb_device *fdev = NULL;
+ int cfd, dfd;
+ int device;
+
+ cfd = open(bus->dirname, O_RDONLY);
+ if (cfd < 0)
+ USB_ERROR_STR(-errno, "couldn't open(%s): %s", bus->dirname,
+ strerror(errno));
+
+ for (device = 1; device < USB_MAX_DEVICES; device++) {
+ struct usb_device_info di;
+ struct usb_device *dev;
+ unsigned char device_desc[DEVICE_DESC_LENGTH];
+ char buf[20];
+
+ di.udi_addr = device;
+ if (ioctl(cfd, USB_DEVICEINFO, &di) < 0)
+ continue;
+
+ /* There's a device; is it one we should mess with? */
+
+ if (strncmp(di.udi_devnames[0], "ugen", 4) != 0)
+ /* best not to play with things we don't understand */
+ continue;
+
+#ifdef __FreeBSD_kernel__
+ snprintf(buf, sizeof(buf) - 1, "/dev/%s", di.udi_devnames[0]);
+#else
+ snprintf(buf, sizeof(buf) - 1, "/dev/%s.00", di.udi_devnames[0]);
+#endif
+
+ /* Open its control endpoint */
+ dfd = open(buf, O_RDONLY);
+ if (dfd < 0) {
+ if (usb_debug >= 2)
+ fprintf(stderr, "usb_os_find_devices: couldn't open device %s: %s\n",
+ buf, strerror(errno));
+ continue;
+ }
+
+ dev = malloc(sizeof(*dev));
+ if (!dev)
+ USB_ERROR(-ENOMEM);
+
+ memset((void *)dev, 0, sizeof(*dev));
+
+ dev->bus = bus;
+
+ /* we need to report the device name as /dev/ugenx NOT /dev/ugenx.00
+ * This seemed easier than having 2 variables...
+ */
+#if (__NetBSD__ || __OpenBSD__)
+ snprintf(buf, sizeof(buf) - 1, "/dev/%s", di.udi_devnames[0]);
+#endif
+
+ strncpy(dev->filename, buf, sizeof(dev->filename) - 1);
+ dev->filename[sizeof(dev->filename) - 1] = 0;
+
+ if (ioctl(dfd, USB_GET_DEVICE_DESC, device_desc) < 0)
+ USB_ERROR_STR(-errno, "couldn't get device descriptor for %s: %s",
+ buf, strerror(errno));
+
+ close(dfd);
+
+ usb_parse_descriptor(device_desc, "bbwbbbbwwwbbbb", &dev->descriptor);
+
+ LIST_ADD(fdev, dev);
+
+ if (usb_debug >= 2)
+ fprintf(stderr, "usb_os_find_devices: Found %s on %s\n",
+ dev->filename, bus->dirname);
+ }
+
+ close(cfd);
+
+ *devices = fdev;
+
+ return 0;
+}
+
+int usb_os_determine_children(struct usb_bus *bus)
+{
+ /* Nothing yet */
+ return 0;
+}
+
+void usb_os_init(void)
+{
+ /* nothing */
+}
+
+int usb_resetep(usb_dev_handle *dev, unsigned int ep)
+{
+ /* Not yet done, because I haven't needed it. */
+
+ USB_ERROR_STR(-ENOSYS, "usb_resetep called, unimplemented on BSD");
+}
+
+int usb_clear_halt(usb_dev_handle *dev, unsigned int ep)
+{
+ /* Not yet done, because I haven't needed it. */
+
+ USB_ERROR_STR(-ENOSYS, "usb_clear_halt called, unimplemented on BSD");
+}
+
+int usb_reset(usb_dev_handle *dev)
+{
+ /* Not yet done, because I haven't needed it. */
+
+ USB_ERROR_STR(-ENOSYS, "usb_reset called, unimplemented on BSD");
+}
+
diff --git a/libusb/config.h b/libusb/config.h
new file mode 100644
index 0000000..bbb1c80
--- /dev/null
+++ b/libusb/config.h
@@ -0,0 +1,98 @@
+/* config.h. Generated by configure. */
+/* config.h.in. Generated from configure.in by autoheader. */
+
+#define LINUX_API 1
+#define BSD_API 0
+#define DARWIN_API 0
+
+/* #undef HAVE_OLD_DEV_USB_USB_H */
+
+#define HAVE_LIMITS_H 1
+#define HAVE_UNISTD_H 1
+#define HAVE_VALUES_H 1
+
+#define LIBUSB_MAJOR_VERSION 0
+#define LIBUSB_MINOR_VERSION 1
+#define LIBUSB_MICRO_VERSION 12
+#define LIBUSB_INTERFACE_AGE 4
+#define LIBUSB_BINARY_AGE 8
+
+
+/* Define to 1 if you have the <dlfcn.h> header file. */
+#define HAVE_DLFCN_H 1
+
+/* Define to 1 if you don't have `vprintf' but do have `_doprnt.' */
+/* #undef HAVE_DOPRNT */
+
+/* Define to 1 if you have the <inttypes.h> header file. */
+#define HAVE_INTTYPES_H 1
+
+/* Define to 1 if you have the <limits.h> header file. */
+#define HAVE_LIMITS_H 1
+
+/* Define to 1 if you have the `memmove' function. */
+#define HAVE_MEMMOVE 1
+
+/* Define to 1 if you have the <memory.h> header file. */
+#define HAVE_MEMORY_H 1
+
+/* Define to 1 if you have the <stdint.h> header file. */
+#define HAVE_STDINT_H 1
+
+/* Define to 1 if you have the <stdlib.h> header file. */
+#define HAVE_STDLIB_H 1
+
+/* Define to 1 if you have the <strings.h> header file. */
+#define HAVE_STRINGS_H 1
+
+/* Define to 1 if you have the <string.h> header file. */
+#define HAVE_STRING_H 1
+
+/* Define to 1 if you have the <sys/stat.h> header file. */
+#define HAVE_SYS_STAT_H 1
+
+/* Define to 1 if you have the <sys/types.h> header file. */
+#define HAVE_SYS_TYPES_H 1
+
+/* Define to 1 if you have the <unistd.h> header file. */
+#define HAVE_UNISTD_H 1
+
+/* Define to 1 if you have the <values.h> header file. */
+#define HAVE_VALUES_H 1
+
+/* Define to 1 if you have the `vprintf' function. */
+#define HAVE_VPRINTF 1
+
+/* Define to 1 if your C compiler doesn't accept -c and -o together. */
+/* #undef NO_MINUS_C_MINUS_O */
+
+/* Name of package */
+#define PACKAGE "libusb"
+
+/* Define to the address where bug reports for this package should be sent. */
+#define PACKAGE_BUGREPORT ""
+
+/* Define to the full name of this package. */
+#define PACKAGE_NAME "libusb"
+
+/* Define to the full name and version of this package. */
+#define PACKAGE_STRING "libusb 0.1.12"
+
+/* Define to the one symbol short name of this package. */
+#define PACKAGE_TARNAME "libusb"
+
+/* Define to the version of this package. */
+#define PACKAGE_VERSION "0.1.12"
+
+/* Define to 1 if you have the ANSI C header files. */
+#define STDC_HEADERS 1
+
+/* Version number of package */
+#define VERSION "0.1.12"
+
+/* Define to 1 if your processor stores words with the most significant byte
+ first (like Motorola and SPARC, unlike Intel and VAX). */
+/* #undef WORDS_BIGENDIAN */
+
+/* Define to empty if `const' does not conform to ANSI C. */
+/* #undef const */
diff --git a/libusb/darwin.c b/libusb/darwin.c
new file mode 100644
index 0000000..6f90ecc
--- /dev/null
+++ b/libusb/darwin.c
@@ -0,0 +1,1209 @@
+/*
+ * Darwin/MacOS X Support
+ *
+ * (c) 2002-2005 Nathan Hjelm <hjelmn@users.sourceforge.net>
+ *
+ * (04/17/2005):
+ * - Lots of minor fixes.
+ * - Endpoint table now made by claim_interface to fix a bug.
+ * - Merged Read/Write to make modifications easier.
+ * (03/25/2005):
+ * - Fixed a bug when using asynchronous callbacks within a multi-threaded application.
+ * (03/14/2005):
+ * - Added an endpoint table to speed up bulk transfers.
+ * 0.1.11 (02/22/2005):
+ * - Updated error checking in read/write routines to check completion codes.
+ * - Updated set_configuration so that the open interface is reclaimed before completion.
+ * - Fixed several typos.
+ * 0.1.8 (01/12/2004):
+ * - Fixed several memory leaks.
+ * - Readded 10.0 support
+ * - Added support for USB fuctions defined in 10.3 and above
+ * (01/02/2003):
+ * - Applied a patch by Philip Edelbrock <phil@edgedesign.us> that fixes a bug in usb_control_msg.
+ * (12/16/2003):
+ * - Even better error printing.
+ * - Devices that cannot be opened can have their interfaces opened.
+ * 0.1.6 (05/12/2002):
+ * - Fixed problem where libusb holds resources after program completion.
+ * - Mouse should no longer freeze up now.
+ * 0.1.2 (02/13/2002):
+ * - Bulk functions should work properly now.
+ * 0.1.1 (02/11/2002):
+ * - Fixed major bug (device and interface need to be released after use)
+ * 0.1.0 (01/06/2002):
+ * - Tested driver with gphoto (works great as long as Image Capture isn't running)
+ * 0.1d (01/04/2002):
+ * - Implimented clear_halt and resetep
+ * - Uploaded to CVS.
+ * 0.1b (01/04/2002):
+ * - Added usb_debug line to bulk read and write function.
+ * 0.1a (01/03/2002):
+ * - Driver mostly completed using the macosx driver I wrote for my rioutil software.
+ *
+ * Derived from Linux version by Richard Tobin.
+ * Also partly derived from BSD version.
+ *
+ * This library is covered by the LGPL, read LICENSE for details.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+
+/* standard includes for darwin/os10 (IOKit) */
+#include <mach/mach_port.h>
+#include <IOKit/IOCFBundle.h>
+#include <IOKit/usb/IOUSBLib.h>
+#include <IOKit/IOCFPlugIn.h>
+
+#include "usbi.h"
+
+/* some defines */
+/* IOUSBInterfaceInferface */
+#if defined (kIOUSBInterfaceInterfaceID220)
+
+// #warning "libusb being compiled for 10.4 or later"
+#define usb_interface_t IOUSBInterfaceInterface220
+#define InterfaceInterfaceID kIOUSBInterfaceInterfaceID220
+#define InterfaceVersion 220
+
+#elif defined (kIOUSBInterfaceInterfaceID197)
+
+// #warning "libusb being compiled for 10.3 or later"
+#define usb_interface_t IOUSBInterfaceInterface197
+#define InterfaceInterfaceID kIOUSBInterfaceInterfaceID197
+#define InterfaceVersion 197
+
+#elif defined (kIOUSBInterfaceInterfaceID190)
+
+// #warning "libusb being compiled for 10.2 or later"
+#define usb_interface_t IOUSBInterfaceInterface190
+#define InterfaceInterfaceID kIOUSBInterfaceInterfaceID190
+#define InterfaceVersion 190
+
+#elif defined (kIOUSBInterfaceInterfaceID182)
+
+// #warning "libusb being compiled for 10.1 or later"
+#define usb_interface_t IOUSBInterfaceInterface182
+#define InterfaceInterfaceID kIOUSBInterfaceInterfaceID182
+#define InterfaceVersion 182
+
+#else
+
+/* No timeout functions available! Time to upgrade your os. */
+#warning "libusb being compiled without support for timeout bulk functions! 10.0 and up"
+#define usb_interface_t IOUSBInterfaceInterface
+#define InterfaceInterfaceID kIOUSBInterfaceInterfaceID
+#define LIBUSB_NO_TIMEOUT_INTERFACE
+#define InterfaceVersion 180
+
+#endif
+
+/* IOUSBDeviceInterface */
+#if defined (kIOUSBDeviceInterfaceID197)
+
+#define usb_device_t IOUSBDeviceInterface197
+#define DeviceInterfaceID kIOUSBDeviceInterfaceID197
+#define DeviceVersion 197
+
+#elif defined (kIOUSBDeviceInterfaceID187)
+
+#define usb_device_t IOUSBDeviceInterface187
+#define DeviceInterfaceID kIOUSBDeviceInterfaceID187
+#define DeviceVersion 187
+
+#elif defined (kIOUSBDeviceInterfaceID182)
+
+#define usb_device_t IOUSBDeviceInterface182
+#define DeviceInterfaceID kIOUSBDeviceInterfaceID182
+#define DeviceVersion 182
+
+#else
+
+#define usb_device_t IOUSBDeviceInterface
+#define DeviceInterfaceID kIOUSBDeviceInterfaceID
+#define LIBUSB_NO_TIMEOUT_DEVICE
+#define LIBUSB_NO_SEIZE_DEVICE
+#define DeviceVersion 180
+
+#endif
+
+typedef IOReturn io_return_t;
+typedef IOCFPlugInInterface *io_cf_plugin_ref_t;
+typedef SInt32 s_int32_t;
+typedef IOReturn (*rw_async_func_t)(void *self, UInt8 pipeRef, void *buf, UInt32 size,
+ IOAsyncCallback1 callback, void *refcon);
+typedef IOReturn (*rw_async_to_func_t)(void *self, UInt8 pipeRef, void *buf, UInt32 size,
+ UInt32 noDataTimeout, UInt32 completionTimeout,
+ IOAsyncCallback1 callback, void *refcon);
+
+#if !defined(IO_OBJECT_NULL)
+#define IO_OBJECT_NULL ((io_object_t)0)
+#endif
+
+/* Darwin/OS X impl does not use fd field, instead it uses this */
+struct darwin_dev_handle {
+ usb_device_t **device;
+ usb_interface_t **interface;
+ int open;
+
+ /* stored translation table for pipes to endpoints */
+ int num_endpoints;
+ unsigned char *endpoint_addrs;
+};
+
+static CFMutableDictionaryRef matchingDict;
+static IONotificationPortRef gNotifyPort;
+static mach_port_t masterPort = MACH_PORT_NULL;
+
+static void darwin_cleanup (void)
+{
+ IONotificationPortDestroy(gNotifyPort);
+ mach_port_deallocate(mach_task_self(), masterPort);
+}
+
+static char *darwin_error_str (int result) {
+ switch (result) {
+ case kIOReturnSuccess:
+ return "no error";
+ case kIOReturnNotOpen:
+ return "device not opened for exclusive access";
+ case kIOReturnNoDevice:
+ return "no connection to an IOService";
+ case kIOUSBNoAsyncPortErr:
+ return "no async port has been opened for interface";
+ case kIOReturnExclusiveAccess:
+ return "another process has device opened for exclusive access";
+ case kIOUSBPipeStalled:
+ return "pipe is stalled";
+ case kIOReturnError:
+ return "could not establish a connection to the Darwin kernel";
+ case kIOUSBTransactionTimeout:
+ return "transaction timed out";
+ case kIOReturnBadArgument:
+ return "invalid argument";
+ case kIOReturnAborted:
+ return "transaction aborted";
+ default:
+ return "unknown error";
+ }
+}
+
+/* not a valid errorno outside darwin.c */
+#define LUSBDARWINSTALL (ELAST+1)
+
+static int darwin_to_errno (int result) {
+ switch (result) {
+ case kIOReturnSuccess:
+ return 0;
+ case kIOReturnNotOpen:
+ return EBADF;
+ case kIOReturnNoDevice:
+ case kIOUSBNoAsyncPortErr:
+ return ENXIO;
+ case kIOReturnExclusiveAccess:
+ return EBUSY;
+ case kIOUSBPipeStalled:
+ return LUSBDARWINSTALL;
+ case kIOReturnBadArgument:
+ return EINVAL;
+ case kIOUSBTransactionTimeout:
+ return ETIMEDOUT;
+ case kIOReturnError:
+ default:
+ return 1;
+ }
+}
+
+static int usb_setup_iterator (io_iterator_t *deviceIterator)
+{
+ int result;
+
+ /* set up the matching dictionary for class IOUSBDevice and its subclasses.
+ It will be consumed by the IOServiceGetMatchingServices call */
+ if ((matchingDict = IOServiceMatching(kIOUSBDeviceClassName)) == NULL) {
+ darwin_cleanup ();
+
+ USB_ERROR_STR(-1, "libusb/darwin.c usb_setup_iterator: Could not create a matching dictionary.\n");
+ }
+
+ result = IOServiceGetMatchingServices(masterPort, matchingDict, deviceIterator);
+ matchingDict = NULL;
+
+ if (result != kIOReturnSuccess)
+ USB_ERROR_STR (-darwin_to_errno (result), "libusb/darwin.c usb_setup_iterator: IOServiceGetMatchingServices: %s\n",
+ darwin_error_str(result));
+
+ return 0;
+}
+
+static usb_device_t **usb_get_next_device (io_iterator_t deviceIterator, UInt32 *locationp)
+{
+ io_cf_plugin_ref_t *plugInInterface = NULL;
+ usb_device_t **device;
+ io_service_t usbDevice;
+ long result, score;
+
+ if (!IOIteratorIsValid (deviceIterator) || !(usbDevice = IOIteratorNext(deviceIterator)))
+ return NULL;
+
+ result = IOCreatePlugInInterfaceForService(usbDevice, kIOUSBDeviceUserClientTypeID,
+ kIOCFPlugInInterfaceID, &plugInInterface,
+ &score);
+
+ result = IOObjectRelease(usbDevice);
+ if (result || !plugInInterface)
+ return NULL;
+
+ (*plugInInterface)->QueryInterface(plugInInterface, CFUUIDGetUUIDBytes(DeviceInterfaceID),
+ (LPVOID)&device);
+
+ (*plugInInterface)->Stop(plugInInterface);
+ IODestroyPlugInInterface (plugInInterface);
+ plugInInterface = NULL;
+
+ (*(device))->GetLocationID(device, locationp);
+
+ return device;
+}
+
+int usb_os_open(usb_dev_handle *dev)
+{
+ struct darwin_dev_handle *device;
+
+ io_return_t result;
+ io_iterator_t deviceIterator;
+
+ usb_device_t **darwin_device;
+
+ UInt32 location = *((UInt32 *)dev->device->dev);
+ UInt32 dlocation;
+
+ if (!dev)
+ USB_ERROR(-ENXIO);
+
+ if (masterPort == MACH_PORT_NULL)
+ USB_ERROR(-EINVAL);
+
+ device = calloc(1, sizeof(struct darwin_dev_handle));
+ if (!device)
+ USB_ERROR(-ENOMEM);
+
+ if (usb_debug > 3)
+ fprintf(stderr, "usb_os_open: %04x:%04x\n",
+ dev->device->descriptor.idVendor,
+ dev->device->descriptor.idProduct);
+
+ if ((result = usb_setup_iterator (&deviceIterator)) < 0)
+ return result;
+
+ /* This port of libusb uses locations to keep track of devices. */
+ while ((darwin_device = usb_get_next_device (deviceIterator, &dlocation)) != NULL) {
+ if (dlocation == location)
+ break;
+
+ (*darwin_device)->Release(darwin_device);
+ }
+
+ IOObjectRelease(deviceIterator);
+ device->device = darwin_device;
+
+ if (device->device == NULL)
+ USB_ERROR_STR (-ENOENT, "usb_os_open: %s\n", "Device not found!");
+
+#if !defined (LIBUSB_NO_SEIZE_DEVICE)
+ result = (*(device->device))->USBDeviceOpenSeize (device->device);
+#else
+ /* No Seize in OS X 10.0 (Darwin 1.4) */
+ result = (*(device->device))->USBDeviceOpen (device->device);
+#endif
+
+ if (result != kIOReturnSuccess) {
+ switch (result) {
+ case kIOReturnExclusiveAccess:
+ if (usb_debug > 0)
+ fprintf (stderr, "usb_os_open(USBDeviceOpenSeize): %s\n", darwin_error_str(result));
+ break;
+ default:
+ (*(device->device))->Release (device->device);
+ USB_ERROR_STR(-darwin_to_errno (result), "usb_os_open(USBDeviceOpenSeize): %s",
+ darwin_error_str(result));
+ }
+
+ device->open = 0;
+ } else
+ device->open = 1;
+
+ dev->impl_info = device;
+ dev->interface = -1;
+ dev->altsetting = -1;
+
+ device->num_endpoints = 0;
+ device->endpoint_addrs = NULL;
+
+ return 0;
+}
+
+int usb_os_close(usb_dev_handle *dev)
+{
+ struct darwin_dev_handle *device;
+ io_return_t result;
+
+ if (!dev)
+ USB_ERROR(-ENXIO);
+
+ if ((device = dev->impl_info) == NULL)
+ USB_ERROR(-ENOENT);
+
+ usb_release_interface(dev, dev->interface);
+
+ if (usb_debug > 3)
+ fprintf(stderr, "usb_os_close: %04x:%04x\n",
+ dev->device->descriptor.idVendor,
+ dev->device->descriptor.idProduct);
+
+ if (device->open == 1)
+ result = (*(device->device))->USBDeviceClose(device->device);
+ else
+ result = kIOReturnSuccess;
+
+ /* device may not need to be released, but if it has to... */
+ (*(device->device))->Release(device->device);
+
+ if (result != kIOReturnSuccess)
+ USB_ERROR_STR(-darwin_to_errno(result), "usb_os_close(USBDeviceClose): %s", darwin_error_str(result));
+
+ free (device);
+
+ return 0;
+}
+
+static int get_endpoints (struct darwin_dev_handle *device)
+{
+ io_return_t ret;
+
+ u_int8_t numep, direction, number;
+ u_int8_t dont_care1, dont_care3;
+ u_int16_t dont_care2;
+
+ int i;
+
+ if (device == NULL || device->interface == NULL)
+ return -EINVAL;
+
+ if (usb_debug > 1)
+ fprintf(stderr, "libusb/darwin.c get_endpoints: building table of endpoints.\n");
+
+ /* retrieve the total number of endpoints on this interface */
+ ret = (*(device->interface))->GetNumEndpoints(device->interface, &numep);
+ if ( ret ) {
+ if ( usb_debug > 1 )
+ fprintf ( stderr, "get_endpoints: interface is %p\n", device->interface );
+
+ USB_ERROR_STR ( -ret, "get_endpoints: can't get number of endpoints for interface" );
+ }
+
+ free (device->endpoint_addrs);
+ device->endpoint_addrs = calloc (sizeof (unsigned char), numep);
+
+ /* iterate through pipe references */
+ for (i = 1 ; i <= numep ; i++) {
+ ret = (*(device->interface))->GetPipeProperties(device->interface, i, &direction, &number,
+ &dont_care1, &dont_care2, &dont_care3);
+
+ if (ret != kIOReturnSuccess) {
+ fprintf (stderr, "get_endpoints: an error occurred getting pipe information on pipe %d\n",
+ i );
+ USB_ERROR_STR(-darwin_to_errno(ret), "get_endpoints(GetPipeProperties): %s", darwin_error_str(ret));
+ }
+
+ if (usb_debug > 1)
+ fprintf (stderr, "get_endpoints: Pipe %i: DIR: %i number: %i\n", i, direction, number);
+
+ device->endpoint_addrs[i - 1] = ((direction << 7 & USB_ENDPOINT_DIR_MASK) |
+ (number & USB_ENDPOINT_ADDRESS_MASK));
+ }
+
+ device->num_endpoints = numep;
+
+ if (usb_debug > 1)
+ fprintf(stderr, "libusb/darwin.c get_endpoints: complete.\n");
+
+ return 0;
+}
+
+static int claim_interface (usb_dev_handle *dev, int interface)
+{
+ io_iterator_t interface_iterator;
+ io_service_t usbInterface = IO_OBJECT_NULL;
+ io_return_t result;
+ io_cf_plugin_ref_t *plugInInterface = NULL;
+
+ IOUSBFindInterfaceRequest request;
+
+ struct darwin_dev_handle *device;
+ long score;
+ int current_interface;
+
+ device = dev->impl_info;
+
+ request.bInterfaceClass = kIOUSBFindInterfaceDontCare;
+ request.bInterfaceSubClass = kIOUSBFindInterfaceDontCare;
+ request.bInterfaceProtocol = kIOUSBFindInterfaceDontCare;
+ request.bAlternateSetting = kIOUSBFindInterfaceDontCare;
+
+ result = (*(device->device))->CreateInterfaceIterator(device->device, &request, &interface_iterator);
+ if (result != kIOReturnSuccess)
+ USB_ERROR_STR (-darwin_to_errno(result), "claim_interface(CreateInterfaceIterator): %s",
+ darwin_error_str(result));
+
+ for ( current_interface=0 ; current_interface <= interface ; current_interface++ ) {
+ usbInterface = IOIteratorNext(interface_iterator);
+ if ( usb_debug > 3 )
+ fprintf ( stderr, "Interface %d of device is 0x%08x\n",
+ current_interface, usbInterface );
+ }
+
+ current_interface--;
+
+ /* the interface iterator is no longer needed, release it */
+ IOObjectRelease(interface_iterator);
+
+ if (!usbInterface) {
+ u_int8_t nConfig; /* Index of configuration to use */
+ IOUSBConfigurationDescriptorPtr configDesc; /* to describe which configuration to select */
+ /* Only a composite class device with no vendor-specific driver will
+ be configured. Otherwise, we need to do it ourselves, or there
+ will be no interfaces for the device. */
+
+ if ( usb_debug > 3 )
+ fprintf ( stderr,"claim_interface: No interface found; selecting configuration\n" );
+
+ result = (*(device->device))->GetNumberOfConfigurations ( device->device, &nConfig );
+ if (result != kIOReturnSuccess)
+ USB_ERROR_STR(-darwin_to_errno(result), "claim_interface(GetNumberOfConfigurations): %s",
+ darwin_error_str(result));
+
+ if (nConfig < 1)
+ USB_ERROR_STR(-ENXIO ,"claim_interface(GetNumberOfConfigurations): no configurations");
+ else if ( nConfig > 1 && usb_debug > 0 )
+ fprintf ( stderr, "claim_interface: device has more than one"
+ " configuration, using the first (warning)\n" );
+
+ if ( usb_debug > 3 )
+ fprintf ( stderr, "claim_interface: device has %d configuration%s\n",
+ (int)nConfig, (nConfig>1?"s":"") );
+
+ /* Always use the first configuration */
+ result = (*(device->device))->GetConfigurationDescriptorPtr ( (device->device), 0, &configDesc );
+ if (result != kIOReturnSuccess) {
+ if (device->open == 1) {
+ (*(device->device))->USBDeviceClose ( (device->device) );
+ (*(device->device))->Release ( (device->device) );
+ }
+
+ USB_ERROR_STR(-darwin_to_errno(result), "claim_interface(GetConfigurationDescriptorPtr): %s",
+ darwin_error_str(result));
+ } else if ( usb_debug > 3 )
+ fprintf ( stderr, "claim_interface: configuration value is %d\n",
+ configDesc->bConfigurationValue );
+
+ if (device->open == 1) {
+ result = (*(device->device))->SetConfiguration ( (device->device), configDesc->bConfigurationValue );
+
+ if (result != kIOReturnSuccess) {
+ (*(device->device))->USBDeviceClose ( (device->device) );
+ (*(device->device))->Release ( (device->device) );
+
+ USB_ERROR_STR(-darwin_to_errno(result), "claim_interface(SetConfiguration): %s",
+ darwin_error_str(result));
+ }
+
+ dev->config = configDesc->bConfigurationValue;
+ }
+
+ request.bInterfaceClass = kIOUSBFindInterfaceDontCare;
+ request.bInterfaceSubClass = kIOUSBFindInterfaceDontCare;
+ request.bInterfaceProtocol = kIOUSBFindInterfaceDontCare;
+ request.bAlternateSetting = kIOUSBFindInterfaceDontCare;
+
+ /* Now go back and get the chosen interface */
+ result = (*(device->device))->CreateInterfaceIterator(device->device, &request, &interface_iterator);
+ if (result != kIOReturnSuccess)
+ USB_ERROR_STR (-darwin_to_errno(result), "claim_interface(CreateInterfaceIterator): %s",
+ darwin_error_str(result));
+
+ for (current_interface = 0 ; current_interface <= interface ; current_interface++) {
+ usbInterface = IOIteratorNext(interface_iterator);
+
+ if ( usb_debug > 3 )
+ fprintf ( stderr, "claim_interface: Interface %d of device is 0x%08x\n",
+ current_interface, usbInterface );
+ }
+ current_interface--;
+
+ /* the interface iterator is no longer needed, release it */
+ IOObjectRelease(interface_iterator);
+
+ if (!usbInterface)
+ USB_ERROR_STR (-ENOENT, "claim_interface: interface iterator returned NULL");
+ }
+
+ result = IOCreatePlugInInterfaceForService(usbInterface,
+ kIOUSBInterfaceUserClientTypeID,
+ kIOCFPlugInInterfaceID,
+ &plugInInterface, &score);
+ /* No longer need the usbInterface object after getting the plug-in */
+ result = IOObjectRelease(usbInterface);
+ if (result || !plugInInterface)
+ USB_ERROR(-ENOENT);
+
+ /* Now create the device interface for the interface */
+ result = (*plugInInterface)->QueryInterface(plugInInterface,
+ CFUUIDGetUUIDBytes(InterfaceInterfaceID),
+ (LPVOID) &device->interface);
+
+ /* No longer need the intermediate plug-in */
+ (*plugInInterface)->Stop(plugInInterface);
+ IODestroyPlugInInterface (plugInInterface);
+
+ if (result != kIOReturnSuccess)
+ USB_ERROR_STR(-darwin_to_errno(result), "claim_interface(QueryInterface): %s",
+ darwin_error_str(result));
+
+ if (!device->interface)
+ USB_ERROR(-EACCES);
+
+ if ( usb_debug > 3 )
+ fprintf ( stderr, "claim_interface: Interface %d of device from QueryInterface is %p\n",
+ current_interface, device->interface);
+
+ /* claim the interface */
+ result = (*(device->interface))->USBInterfaceOpen(device->interface);
+ if (result)
+ USB_ERROR_STR(-darwin_to_errno(result), "claim_interface(USBInterfaceOpen): %s",
+ darwin_error_str(result));
+
+ result = get_endpoints (device);
+
+ if (result) {
+ /* this should not happen */
+ usb_release_interface (dev, interface);
+ USB_ERROR_STR ( result, "claim_interface: could not build endpoint table");
+ }
+
+ return 0;
+}
+
+int usb_set_configuration (usb_dev_handle *dev, int configuration)
+{
+ struct darwin_dev_handle *device;
+ io_return_t result;
+ int interface;
+
+ if ( usb_debug > 3 )
+ fprintf ( stderr, "usb_set_configuration: called for config %x\n", configuration );
+
+ if (!dev)
+ USB_ERROR_STR ( -ENXIO, "usb_set_configuration: called with null device\n" );
+
+ if ((device = dev->impl_info) == NULL)
+ USB_ERROR_STR ( -ENOENT, "usb_set_configuration: device not properly initialized" );
+
+ /* Setting configuration will invalidate the interface, so we need
+ to reclaim it. First, dispose of existing interface, if any. */
+ interface = dev->interface;
+
+ if ( device->interface )
+ usb_release_interface(dev, dev->interface);
+
+ result = (*(device->device))->SetConfiguration(device->device, configuration);
+
+ if (result)
+ USB_ERROR_STR(-darwin_to_errno(result), "usb_set_configuration(SetConfiguration): %s",
+ darwin_error_str(result));
+
+ /* Reclaim interface */
+ if (interface != -1)
+ result = usb_claim_interface (dev, interface);
+
+ dev->config = configuration;
+
+ return result;
+}
+
+int usb_claim_interface(usb_dev_handle *dev, int interface)
+{
+ struct darwin_dev_handle *device = dev->impl_info;
+
+ io_return_t result;
+
+ if ( usb_debug > 3 )
+ fprintf ( stderr, "usb_claim_interface: called for interface %d\n", interface );
+
+ if (!device)
+ USB_ERROR_STR ( -ENOENT, "usb_claim_interface: device is NULL" );
+
+ if (!(device->device))
+ USB_ERROR_STR ( -EINVAL, "usb_claim_interface: device->device is NULL" );
+
+ /* If we have already claimed an interface, release it */
+ if ( device->interface )
+ usb_release_interface(dev, dev->interface);
+
+ result = claim_interface ( dev, interface );
+ if ( result )
+ USB_ERROR_STR ( result, "usb_claim_interface: couldn't claim interface" );
+
+ dev->interface = interface;
+
+ /* interface is claimed and async IO is set up: return 0 */
+ return 0;
+}
+
+int usb_release_interface(usb_dev_handle *dev, int interface)
+{
+ struct darwin_dev_handle *device;
+ io_return_t result;
+
+ if (!dev)
+ USB_ERROR(-ENXIO);
+
+ if ((device = dev->impl_info) == NULL)
+ USB_ERROR(-ENOENT);
+
+ /* interface is not open */
+ if (!device->interface)
+ return 0;
+
+ result = (*(device->interface))->USBInterfaceClose(device->interface);
+
+ if (result != kIOReturnSuccess)
+ USB_ERROR_STR(-darwin_to_errno(result), "usb_release_interface(USBInterfaceClose): %s",
+ darwin_error_str(result));
+
+ result = (*(device->interface))->Release(device->interface);
+
+ if (result != kIOReturnSuccess)
+ USB_ERROR_STR(-darwin_to_errno(result), "usb_release_interface(Release): %s",
+ darwin_error_str(result));
+
+ device->interface = NULL;
+
+ free (device->endpoint_addrs);
+
+ device->num_endpoints = 0;
+ device->endpoint_addrs = NULL;
+
+ dev->interface = -1;
+ dev->altsetting = -1;
+
+ return 0;
+}
+
+int usb_set_altinterface(usb_dev_handle *dev, int alternate)
+{
+ struct darwin_dev_handle *device;
+ io_return_t result;
+
+ if (!dev)
+ USB_ERROR(-ENXIO);
+
+ if ((device = dev->impl_info) == NULL)
+ USB_ERROR(-ENOENT);
+
+ /* interface is not open */
+ if (!device->interface)
+ USB_ERROR_STR(-EACCES, "usb_set_altinterface: interface used without being claimed");
+
+ result = (*(device->interface))->SetAlternateInterface(device->interface, alternate);
+
+ if (result)
+ USB_ERROR_STR(result, "usb_set_altinterface: could not set alternate interface");
+
+ dev->altsetting = alternate;
+
+ result = get_endpoints (device);
+ if (result) {
+ /* this should not happen */
+ USB_ERROR_STR ( result, "usb_set_altinterface: could not build endpoint table");
+ }
+
+ return 0;
+}
+
+/* simple function that figures out what pipeRef is associated with an endpoint */
+static int ep_to_pipeRef (struct darwin_dev_handle *device, int ep)
+{
+ int i;
+
+ if (usb_debug > 1)
+ fprintf(stderr, "libusb/darwin.c ep_to_pipeRef: Converting ep address to pipeRef.\n");
+
+ for (i = 0 ; i < device->num_endpoints ; i++)
+ if (device->endpoint_addrs[i] == ep)
+ return i + 1;
+
+ /* No pipe found with the correct endpoint address */
+ if (usb_debug > 1)
+ fprintf(stderr, "libusb/darwin.c ep_to_pipeRef: No pipeRef found with endpoint address 0x%02x.\n", ep);
+
+ return -1;
+}
+
+/* argument to handle multiple parameters to rw_completed */
+struct rw_complete_arg {
+ UInt32 io_size;
+ IOReturn result;
+ CFRunLoopRef cf_loop;
+};
+
+static void rw_completed(void *refcon, io_return_t result, void *io_size)
+{
+ struct rw_complete_arg *rw_arg = (struct rw_complete_arg *)refcon;
+
+ if (usb_debug > 2)
+ fprintf(stderr, "io async operation completed: %s, size=%lu, result=0x%08x\n", darwin_error_str(result),
+ (UInt32)io_size, result);
+
+ rw_arg->io_size = (UInt32)io_size;
+ rw_arg->result = result;
+
+ CFRunLoopStop(rw_arg->cf_loop);
+}
+
+static int usb_bulk_transfer (usb_dev_handle *dev, int ep, char *bytes, int size, int timeout,
+ rw_async_func_t rw_async, rw_async_to_func_t rw_async_to)
+{
+ struct darwin_dev_handle *device;
+
+ io_return_t result = -1;
+
+ CFRunLoopSourceRef cfSource;
+ int pipeRef;
+
+ struct rw_complete_arg rw_arg;
+
+ u_int8_t transferType;
+
+ /* None of the values below are used in libusb for bulk transfers */
+ u_int8_t direction, number, interval;
+ u_int16_t maxPacketSize;
+
+ if (!dev)
+ USB_ERROR_STR ( -ENXIO, "usb_bulk_transfer: Called with NULL device" );
+
+ if ((device = dev->impl_info) == NULL)
+ USB_ERROR_STR ( -ENOENT, "usb_bulk_transfer: Device not open" );
+
+ /* interface is not open */
+ if (!device->interface)
+ USB_ERROR_STR(-EACCES, "usb_bulk_transfer: Interface used before it was opened");
+
+
+ /* Set up transfer */
+ if ((pipeRef = ep_to_pipeRef(device, ep)) < 0)
+ USB_ERROR_STR ( -EINVAL, "usb_bulk_transfer: Invalid pipe reference" );
+
+ (*(device->interface))->GetPipeProperties (device->interface, pipeRef, &direction, &number,
+ &transferType, &maxPacketSize, &interval);
+
+ (*(device->interface))->CreateInterfaceAsyncEventSource(device->interface, &cfSource);
+ CFRunLoopAddSource(CFRunLoopGetCurrent(), cfSource, kCFRunLoopDefaultMode);
+
+ bzero((void *)&rw_arg, sizeof(struct rw_complete_arg));
+ rw_arg.cf_loop = CFRunLoopGetCurrent();
+ /* Transfer set up complete */
+
+ if (usb_debug > 0)
+ fprintf (stderr, "libusb/darwin.c usb_bulk_transfer: Transfering %i bytes of data on endpoint 0x%02x\n",
+ size, ep);
+
+ /* Bulk transfer */
+ if (transferType == kUSBInterrupt && usb_debug > 3)
+ fprintf (stderr, "libusb/darwin.c usb_bulk_transfer: USB pipe is an interrupt pipe. Timeouts will not be used.\n");
+
+ if ( transferType != kUSBInterrupt && rw_async_to != NULL)
+
+ result = rw_async_to (device->interface, pipeRef, bytes, size, timeout, timeout,
+ (IOAsyncCallback1)rw_completed, (void *)&rw_arg);
+ else
+ result = rw_async (device->interface, pipeRef, bytes, size, (IOAsyncCallback1)rw_completed,
+ (void *)&rw_arg);
+
+ if (result == kIOReturnSuccess) {
+ /* wait for write to complete */
+ if (CFRunLoopRunInMode(kCFRunLoopDefaultMode, (timeout+999)/1000, true) == kCFRunLoopRunTimedOut) {
+ (*(device->interface))->AbortPipe(device->interface, pipeRef);
+ CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0, true); /* Pick up aborted callback */
+ if (usb_debug)
+ fprintf(stderr, "usb_bulk_read: input timed out\n");
+ }
+ }
+
+ CFRunLoopRemoveSource(CFRunLoopGetCurrent(), cfSource, kCFRunLoopDefaultMode);
+
+ /* Check the return code of both the write and completion functions. */
+ if (result != kIOReturnSuccess || (rw_arg.result != kIOReturnSuccess &&
+ rw_arg.result != kIOReturnAborted) ) {
+ int error_code;
+ char *error_str;
+
+ if (result == kIOReturnSuccess) {
+ error_code = darwin_to_errno (rw_arg.result);
+ error_str = darwin_error_str (rw_arg.result);
+ } else {
+ error_code = darwin_to_errno(result);
+ error_str = darwin_error_str (result);
+ }
+
+ if (transferType != kUSBInterrupt && rw_async_to != NULL)
+ USB_ERROR_STR(-error_code, "usb_bulk_transfer (w/ Timeout): %s", error_str);
+ else
+ USB_ERROR_STR(-error_code, "usb_bulk_transfer (No Timeout): %s", error_str);
+ }
+
+ return rw_arg.io_size;
+}
+
+int usb_bulk_write(usb_dev_handle *dev, int ep, char *bytes, int size, int timeout)
+{
+ int result;
+ rw_async_to_func_t to_func = NULL;
+ struct darwin_dev_handle *device;
+
+ if (dev == NULL || dev->impl_info == NULL)
+ return -EINVAL;
+
+ device = dev->impl_info;
+
+#if !defined (LIBUSB_NO_TIMEOUT_INTERFACE)
+ to_func = (*(device->interface))->WritePipeAsyncTO;
+#endif
+
+ if ((result = usb_bulk_transfer (dev, ep, bytes, size, timeout,
+ (*(device->interface))->WritePipeAsync, to_func)) < 0)
+ USB_ERROR_STR (result, "usb_bulk_write: An error occured during write (see messages above)");
+
+ return result;
+}
+
+int usb_bulk_read(usb_dev_handle *dev, int ep, char *bytes, int size, int timeout)
+{
+ int result;
+ rw_async_to_func_t to_func = NULL;
+ struct darwin_dev_handle *device;
+
+ if (dev == NULL || dev->impl_info == NULL)
+ return -EINVAL;
+
+ ep |= 0x80;
+
+ device = dev->impl_info;
+
+#if !defined (LIBUSB_NO_TIMEOUT_INTERFACE)
+ to_func = (*(device->interface))->ReadPipeAsyncTO;
+#endif
+
+ if ((result = usb_bulk_transfer (dev, ep, bytes, size, timeout,
+ (*(device->interface))->ReadPipeAsync, to_func)) < 0)
+ USB_ERROR_STR (result, "usb_bulk_read: An error occured during read (see messages above)");
+
+ return result;
+}
+
+/* interrupt endpoints seem to be treated just like any other endpoint under OSX/Darwin */
+int usb_interrupt_write(usb_dev_handle *dev, int ep, char *bytes, int size,
+ int timeout)
+{
+ return usb_bulk_write (dev, ep, bytes, size, timeout);
+}
+
+int usb_interrupt_read(usb_dev_handle *dev, int ep, char *bytes, int size,
+ int timeout)
+{
+ return usb_bulk_read (dev, ep, bytes, size, timeout);
+}
+
+int usb_control_msg(usb_dev_handle *dev, int requesttype, int request,
+ int value, int index, char *bytes, int size, int timeout)
+{
+ struct darwin_dev_handle *device = dev->impl_info;
+
+ io_return_t result;
+
+#if !defined (LIBUSB_NO_TIMEOUT_DEVICE)
+ IOUSBDevRequestTO urequest;
+#else
+ IOUSBDevRequest urequest;
+#endif
+
+ if (usb_debug >= 3)
+ fprintf(stderr, "usb_control_msg: %d %d %d %d %p %d %d\n",
+ requesttype, request, value, index, bytes, size, timeout);
+
+ bzero(&urequest, sizeof(urequest));
+
+ urequest.bmRequestType = requesttype;
+ urequest.bRequest = request;
+ urequest.wValue = value;
+ urequest.wIndex = index;
+ urequest.wLength = size;
+ urequest.pData = bytes;
+#if !defined (LIBUSB_NO_TIMEOUT_DEVICE)
+ urequest.completionTimeout = timeout;
+ urequest.noDataTimeout = timeout;
+
+ result = (*(device->device))->DeviceRequestTO(device->device, &urequest);
+#else
+ result = (*(device->device))->DeviceRequest(device->device, &urequest);
+#endif
+ if (result != kIOReturnSuccess)
+ USB_ERROR_STR(-darwin_to_errno(result), "usb_control_msg(DeviceRequestTO): %s", darwin_error_str(result));
+
+ /* Bytes transfered is stored in the wLenDone field*/
+ return urequest.wLenDone;
+}
+
+int usb_os_find_busses(struct usb_bus **busses)
+{
+ struct usb_bus *fbus = NULL;
+
+ io_iterator_t deviceIterator;
+ io_return_t result;
+
+ usb_device_t **device;
+
+ UInt32 location;
+
+ char buf[20];
+ int i = 1;
+
+ /* Create a master port for communication with IOKit (this should
+ have been created if the user called usb_init() )*/
+ if (masterPort == MACH_PORT_NULL) {
+ usb_init ();
+
+ if (masterPort == MACH_PORT_NULL)
+ USB_ERROR(-ENOENT);
+ }
+
+ if ((result = usb_setup_iterator (&deviceIterator)) < 0)
+ return result;
+
+ while ((device = usb_get_next_device (deviceIterator, &location)) != NULL) {
+ struct usb_bus *bus;
+
+ if (location & 0x00ffffff)
+ continue;
+
+ bus = calloc(1, sizeof(struct usb_bus));
+ if (bus == NULL)
+ USB_ERROR(-ENOMEM);
+
+ sprintf(buf, "%03i", i++);
+ bus->location = location;
+
+ strncpy(bus->dirname, buf, sizeof(bus->dirname) - 1);
+ bus->dirname[sizeof(bus->dirname) - 1] = 0;
+
+ LIST_ADD(fbus, bus);
+
+ if (usb_debug >= 2)
+ fprintf(stderr, "usb_os_find_busses: Found %s\n", bus->dirname);
+
+ (*(device))->Release(device);
+ }
+
+ IOObjectRelease(deviceIterator);
+
+ *busses = fbus;
+
+ return 0;
+}
+
+int usb_os_find_devices(struct usb_bus *bus, struct usb_device **devices)
+{
+ struct usb_device *fdev = NULL;
+
+ io_iterator_t deviceIterator;
+ io_return_t result;
+
+ usb_device_t **device;
+
+ u_int16_t address;
+ UInt32 location;
+ UInt32 bus_loc = bus->location;
+
+ /* for use in retrieving device description */
+ IOUSBDevRequest req;
+
+ /* a master port should have been created by usb_os_init */
+ if (masterPort == MACH_PORT_NULL)
+ USB_ERROR(-ENOENT);
+
+ if ((result = usb_setup_iterator (&deviceIterator)) < 0)
+ return result;
+
+ /* Set up request for device descriptor */
+ req.bmRequestType = USBmakebmRequestType(kUSBIn, kUSBStandard, kUSBDevice);
+ req.bRequest = kUSBRqGetDescriptor;
+ req.wValue = kUSBDeviceDesc << 8;
+ req.wIndex = 0;
+ req.wLength = sizeof(IOUSBDeviceDescriptor);
+
+
+ while ((device = usb_get_next_device (deviceIterator, &location)) != NULL) {
+ unsigned char device_desc[DEVICE_DESC_LENGTH];
+
+ result = (*(device))->GetDeviceAddress(device, (USBDeviceAddress *)&address);
+
+ if (usb_debug >= 2)
+ fprintf(stderr, "usb_os_find_devices: Found USB device at location 0x%08lx\n", location);
+
+ /* first byte of location appears to be associated with the device's bus */
+ if (location >> 24 == bus_loc >> 24) {
+ struct usb_device *dev;
+
+ dev = calloc(1, sizeof(struct usb_device));
+ if (dev == NULL)
+ USB_ERROR(-ENOMEM);
+
+ dev->bus = bus;
+
+ req.pData = device_desc;
+ result = (*(device))->DeviceRequest(device, &req);
+
+ usb_parse_descriptor(device_desc, "bbwbbbbwwwbbbb", &dev->descriptor);
+
+ sprintf(dev->filename, "%03i-%04x-%04x-%02x-%02x", address,
+ dev->descriptor.idVendor, dev->descriptor.idProduct,
+ dev->descriptor.bDeviceClass, dev->descriptor.bDeviceSubClass);
+
+ dev->dev = (USBDeviceAddress *)malloc(4);
+ memcpy(dev->dev, &location, 4);
+
+ LIST_ADD(fdev, dev);
+
+ if (usb_debug >= 2)
+ fprintf(stderr, "usb_os_find_devices: Found %s on %s at location 0x%08lx\n",
+ dev->filename, bus->dirname, location);
+ }
+
+ /* release the device now */
+ (*(device))->Release(device);
+ }
+
+ IOObjectRelease(deviceIterator);
+
+ *devices = fdev;
+
+ return 0;
+}
+
+int usb_os_determine_children(struct usb_bus *bus)
+{
+ /* Nothing yet */
+ return 0;
+}
+
+void usb_os_init(void)
+{
+ if (masterPort == MACH_PORT_NULL) {
+ IOMasterPort(masterPort, &masterPort);
+
+ gNotifyPort = IONotificationPortCreate(masterPort);
+ }
+}
+
+void usb_os_cleanup (void)
+{
+ if (masterPort != MACH_PORT_NULL)
+ darwin_cleanup ();
+}
+
+int usb_resetep(usb_dev_handle *dev, unsigned int ep)
+{
+ struct darwin_dev_handle *device;
+
+ io_return_t result = -1;
+
+ int pipeRef;
+
+ if (!dev)
+ USB_ERROR(-ENXIO);
+
+ if ((device = dev->impl_info) == NULL)
+ USB_ERROR(-ENOENT);
+
+ /* interface is not open */
+ if (!device->interface)
+ USB_ERROR_STR(-EACCES, "usb_resetep: interface used without being claimed");
+
+ if ((pipeRef = ep_to_pipeRef(device, ep)) == -1)
+ USB_ERROR(-EINVAL);
+
+ result = (*(device->interface))->ResetPipe(device->interface, pipeRef);
+
+ if (result != kIOReturnSuccess)
+ USB_ERROR_STR(-darwin_to_errno(result), "usb_resetep(ResetPipe): %s", darwin_error_str(result));
+
+ return 0;
+}
+
+int usb_clear_halt(usb_dev_handle *dev, unsigned int ep)
+{
+ struct darwin_dev_handle *device;
+
+ io_return_t result = -1;
+
+ int pipeRef;
+
+ if (!dev)
+ USB_ERROR(-ENXIO);
+
+ if ((device = dev->impl_info) == NULL)
+ USB_ERROR(-ENOENT);
+
+ /* interface is not open */
+ if (!device->interface)
+ USB_ERROR_STR(-EACCES, "usb_clear_halt: interface used without being claimed");
+
+ if ((pipeRef = ep_to_pipeRef(device, ep)) == -1)
+ USB_ERROR(-EINVAL);
+
+ result = (*(device->interface))->ClearPipeStall(device->interface, pipeRef);
+
+ if (result != kIOReturnSuccess)
+ USB_ERROR_STR(-darwin_to_errno(result), "usb_clear_halt(ClearPipeStall): %s", darwin_error_str(result));
+
+ return 0;
+}
+
+int usb_reset(usb_dev_handle *dev)
+{
+ struct darwin_dev_handle *device;
+
+ io_return_t result;
+
+ if (!dev)
+ USB_ERROR(-ENXIO);
+
+ if ((device = dev->impl_info) == NULL)
+ USB_ERROR(-ENOENT);
+
+ if (!device->device)
+ USB_ERROR_STR(-ENOENT, "usb_reset: no such device");
+
+ result = (*(device->device))->ResetDevice(device->device);
+
+ if (result != kIOReturnSuccess)
+ USB_ERROR_STR(-darwin_to_errno(result), "usb_reset(ResetDevice): %s", darwin_error_str(result));
+
+ return 0;
+}
diff --git a/libusb/descriptors.c b/libusb/descriptors.c
new file mode 100644
index 0000000..0146a82
--- /dev/null
+++ b/libusb/descriptors.c
@@ -0,0 +1,520 @@
+/*
+ * Parses descriptors
+ *
+ * Copyright (c) 2001 Johannes Erdfelt <johannes@erdfelt.com>
+ *
+ * This library is covered by the LGPL, read LICENSE for details.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdint.h>
+#include "usbi.h"
+
+int usb_get_descriptor_by_endpoint(usb_dev_handle *udev, int ep,
+ unsigned char type, unsigned char index, void *buf, int size)
+{
+ memset(buf, 0, size);
+
+ return usb_control_msg(udev, ep | USB_ENDPOINT_IN, USB_REQ_GET_DESCRIPTOR,
+ (type << 8) + index, 0, buf, size, 1000);
+}
+
+int usb_get_descriptor(usb_dev_handle *udev, unsigned char type,
+ unsigned char index, void *buf, int size)
+{
+ memset(buf, 0, size);
+
+ return usb_control_msg(udev, USB_ENDPOINT_IN, USB_REQ_GET_DESCRIPTOR,
+ (type << 8) + index, 0, buf, size, 1000);
+}
+
+int usb_parse_descriptor(unsigned char *source, char *description, void *dest)
+{
+ unsigned char *sp = source, *dp = dest;
+ uint16_t w;
+ uint32_t d;
+ char *cp;
+
+ for (cp = description; *cp; cp++) {
+ switch (*cp) {
+ case 'b': /* 8-bit byte */
+ *dp++ = *sp++;
+ break;
+ case 'w': /* 16-bit word, convert from little endian to CPU */
+ w = (sp[1] << 8) | sp[0]; sp += 2;
+ dp += ((unsigned long)dp & 1); /* Align to word boundary */
+ *((uint16_t *)dp) = w; dp += 2;
+ break;
+ case 'd': /* 32-bit dword, convert from little endian to CPU */
+ d = (sp[3] << 24) | (sp[2] << 16) | (sp[1] << 8) | sp[0]; sp += 4;
+ dp += ((unsigned long)dp & 2); /* Align to dword boundary */
+ *((uint32_t *)dp) = d; dp += 4;
+ break;
+ /* These two characters are undocumented and just a hack for Linux */
+ case 'W': /* 16-bit word, keep CPU endianess */
+ dp += ((unsigned long)dp & 1); /* Align to word boundary */
+ memcpy(dp, sp, 2); sp += 2; dp += 2;
+ break;
+ case 'D': /* 32-bit dword, keep CPU endianess */
+ dp += ((unsigned long)dp & 2); /* Align to dword boundary */
+ memcpy(dp, sp, 4); sp += 4; dp += 4;
+ break;
+ }
+ }
+
+ return sp - source;
+}
+
+/*
+ * This code looks surprisingly similar to the code I wrote for the Linux
+ * kernel. It's not a coincidence :)
+ */
+
+static int usb_parse_endpoint(struct usb_endpoint_descriptor *endpoint, unsigned char *buffer, int size)
+{
+ struct usb_descriptor_header header;
+ unsigned char *begin;
+ int parsed = 0, len, numskipped;
+
+ usb_parse_descriptor(buffer, "bb", &header);
+
+ /* Everything should be fine being passed into here, but we sanity */
+ /* check JIC */
+ if (header.bLength > size) {
+ if (usb_debug >= 1)
+ fprintf(stderr, "ran out of descriptors parsing\n");
+ return -1;
+ }
+
+ if (header.bDescriptorType != USB_DT_ENDPOINT) {
+ if (usb_debug >= 2)
+ fprintf(stderr, "unexpected descriptor 0x%X, expecting endpoint descriptor, type 0x%X\n",
+ header.bDescriptorType, USB_DT_ENDPOINT);
+ return parsed;
+ }
+
+ if (header.bLength >= ENDPOINT_AUDIO_DESC_LENGTH)
+ usb_parse_descriptor(buffer, "bbbbwbbb", endpoint);
+ else if (header.bLength >= ENDPOINT_DESC_LENGTH)
+ usb_parse_descriptor(buffer, "bbbbwb", endpoint);
+
+ buffer += header.bLength;
+ size -= header.bLength;
+ parsed += header.bLength;
+
+ /* Skip over the rest of the Class Specific or Vendor Specific */
+ /* descriptors */
+ begin = buffer;
+ numskipped = 0;
+ while (size >= DESC_HEADER_LENGTH) {
+ usb_parse_descriptor(buffer, "bb", &header);
+
+ if (header.bLength < 2) {
+ if (usb_debug >= 1)
+ fprintf(stderr, "invalid descriptor length of %d\n", header.bLength);
+ return -1;
+ }
+
+ /* If we find another "proper" descriptor then we're done */
+ if ((header.bDescriptorType == USB_DT_ENDPOINT) ||
+ (header.bDescriptorType == USB_DT_INTERFACE) ||
+ (header.bDescriptorType == USB_DT_CONFIG) ||
+ (header.bDescriptorType == USB_DT_DEVICE))
+ break;
+
+ if (usb_debug >= 1)
+ fprintf(stderr, "skipping descriptor 0x%X\n", header.bDescriptorType);
+ numskipped++;
+
+ buffer += header.bLength;
+ size -= header.bLength;
+ parsed += header.bLength;
+ }
+
+ if (numskipped && usb_debug >= 2)
+ fprintf(stderr, "skipped %d class/vendor specific endpoint descriptors\n", numskipped);
+
+ /* Copy any unknown descriptors into a storage area for drivers */
+ /* to later parse */
+ len = (int)(buffer - begin);
+ if (!len) {
+ endpoint->extra = NULL;
+ endpoint->extralen = 0;
+ return parsed;
+ }
+
+ endpoint->extra = malloc(len);
+ if (!endpoint->extra) {
+ if (usb_debug >= 1)
+ fprintf(stderr, "couldn't allocate memory for endpoint extra descriptors\n");
+ endpoint->extralen = 0;
+ return parsed;
+ }
+
+ memcpy(endpoint->extra, begin, len);
+ endpoint->extralen = len;
+
+ return parsed;
+}
+
+static int usb_parse_interface(struct usb_interface *interface,
+ unsigned char *buffer, int size)
+{
+ int i, len, numskipped, retval, parsed = 0;
+ struct usb_descriptor_header header;
+ struct usb_interface_descriptor *ifp;
+ unsigned char *begin;
+
+ interface->num_altsetting = 0;
+
+ while (size >= INTERFACE_DESC_LENGTH) {
+ interface->altsetting = realloc(interface->altsetting, sizeof(struct usb_interface_descriptor) * (interface->num_altsetting + 1));
+ if (!interface->altsetting) {
+ if (usb_debug >= 1)
+ fprintf(stderr, "couldn't malloc interface->altsetting\n");
+ return -1;
+ }
+
+ ifp = interface->altsetting + interface->num_altsetting;
+ interface->num_altsetting++;
+
+ usb_parse_descriptor(buffer, "bbbbbbbbb", ifp);
+
+ /* Skip over the interface */
+ buffer += ifp->bLength;
+ parsed += ifp->bLength;
+ size -= ifp->bLength;
+
+ begin = buffer;
+ numskipped = 0;
+
+ /* Skip over any interface, class or vendor descriptors */
+ while (size >= DESC_HEADER_LENGTH) {
+ usb_parse_descriptor(buffer, "bb", &header);
+
+ if (header.bLength < 2) {
+ if (usb_debug >= 1)
+ fprintf(stderr, "invalid descriptor length of %d\n", header.bLength);
+ return -1;
+ }
+
+ /* If we find another "proper" descriptor then we're done */
+ if ((header.bDescriptorType == USB_DT_INTERFACE) ||
+ (header.bDescriptorType == USB_DT_ENDPOINT) ||
+ (header.bDescriptorType == USB_DT_CONFIG) ||
+ (header.bDescriptorType == USB_DT_DEVICE))
+ break;
+
+ numskipped++;
+
+ buffer += header.bLength;
+ parsed += header.bLength;
+ size -= header.bLength;
+ }
+
+ if (numskipped && usb_debug >= 2)
+ fprintf(stderr, "skipped %d class/vendor specific interface descriptors\n", numskipped);
+
+ /* Copy any unknown descriptors into a storage area for */
+ /* drivers to later parse */
+ len = (int)(buffer - begin);
+ if (!len) {
+ ifp->extra = NULL;
+ ifp->extralen = 0;
+ } else {
+ ifp->extra = malloc(len);
+ if (!ifp->extra) {
+ if (usb_debug >= 1)
+ fprintf(stderr, "couldn't allocate memory for interface extra descriptors\n");
+ ifp->extralen = 0;
+ return -1;
+ }
+ memcpy(ifp->extra, begin, len);
+ ifp->extralen = len;
+ }
+
+ /* Did we hit an unexpected descriptor? */
+ usb_parse_descriptor(buffer, "bb", &header);
+ if ((size >= DESC_HEADER_LENGTH) &&
+ ((header.bDescriptorType == USB_DT_CONFIG) ||
+ (header.bDescriptorType == USB_DT_DEVICE)))
+ return parsed;
+
+ if (ifp->bNumEndpoints > USB_MAXENDPOINTS) {
+ if (usb_debug >= 1)
+ fprintf(stderr, "too many endpoints\n");
+ return -1;
+ }
+
+ if (ifp->bNumEndpoints > 0) {
+ ifp->endpoint = (struct usb_endpoint_descriptor *)
+ malloc(ifp->bNumEndpoints *
+ sizeof(struct usb_endpoint_descriptor));
+ if (!ifp->endpoint) {
+ if (usb_debug >= 1)
+ fprintf(stderr, "couldn't allocate memory for ifp->endpoint\n");
+ return -1;
+ }
+
+ memset(ifp->endpoint, 0, ifp->bNumEndpoints *
+ sizeof(struct usb_endpoint_descriptor));
+
+ for (i = 0; i < ifp->bNumEndpoints; i++) {
+ usb_parse_descriptor(buffer, "bb", &header);
+
+ if (header.bLength > size) {
+ if (usb_debug >= 1)
+ fprintf(stderr, "ran out of descriptors parsing\n");
+ return -1;
+ }
+
+ retval = usb_parse_endpoint(ifp->endpoint + i, buffer, size);
+ if (retval < 0)
+ return retval;
+
+ buffer += retval;
+ parsed += retval;
+ size -= retval;
+ }
+ } else
+ ifp->endpoint = NULL;
+
+ /* We check to see if it's an alternate to this one */
+ ifp = (struct usb_interface_descriptor *)buffer;
+ if (size < USB_DT_INTERFACE_SIZE ||
+ ifp->bDescriptorType != USB_DT_INTERFACE ||
+ !ifp->bAlternateSetting)
+ return parsed;
+ }
+
+ return parsed;
+}
+
+int usb_parse_configuration(struct usb_config_descriptor *config,
+ unsigned char *buffer)
+{
+ int i, retval, size;
+ struct usb_descriptor_header header;
+
+ usb_parse_descriptor(buffer, "bbwbbbbb", config);
+ size = config->wTotalLength;
+
+ if (config->bNumInterfaces > USB_MAXINTERFACES) {
+ if (usb_debug >= 1)
+ fprintf(stderr, "too many interfaces\n");
+ return -1;
+ }
+
+ config->interface = (struct usb_interface *)
+ malloc(config->bNumInterfaces *
+ sizeof(struct usb_interface));
+ if (!config->interface) {
+ if (usb_debug >= 1)
+ fprintf(stderr, "out of memory\n");
+ return -1;
+ }
+
+ memset(config->interface, 0, config->bNumInterfaces * sizeof(struct usb_interface));
+
+ buffer += config->bLength;
+ size -= config->bLength;
+
+ config->extra = NULL;
+ config->extralen = 0;
+
+ for (i = 0; i < config->bNumInterfaces; i++) {
+ int numskipped, len;
+ unsigned char *begin;
+
+ /* Skip over the rest of the Class Specific or Vendor */
+ /* Specific descriptors */
+ begin = buffer;
+ numskipped = 0;
+ while (size >= DESC_HEADER_LENGTH) {
+ usb_parse_descriptor(buffer, "bb", &header);
+
+ if ((header.bLength > size) || (header.bLength < DESC_HEADER_LENGTH)) {
+ if (usb_debug >= 1)
+ fprintf(stderr, "invalid descriptor length of %d\n", header.bLength);
+ return -1;
+ }
+
+ /* If we find another "proper" descriptor then we're done */
+ if ((header.bDescriptorType == USB_DT_ENDPOINT) ||
+ (header.bDescriptorType == USB_DT_INTERFACE) ||
+ (header.bDescriptorType == USB_DT_CONFIG) ||
+ (header.bDescriptorType == USB_DT_DEVICE))
+ break;
+
+ if (usb_debug >= 2)
+ fprintf(stderr, "skipping descriptor 0x%X\n", header.bDescriptorType);
+ numskipped++;
+
+ buffer += header.bLength;
+ size -= header.bLength;
+ }
+
+ if (numskipped && usb_debug >= 2)
+ fprintf(stderr, "skipped %d class/vendor specific endpoint descriptors\n", numskipped);
+
+ /* Copy any unknown descriptors into a storage area for */
+ /* drivers to later parse */
+ len = (int)(buffer - begin);
+ if (len) {
+ /* FIXME: We should realloc and append here */
+ if (!config->extralen) {
+ config->extra = malloc(len);
+ if (!config->extra) {
+ if (usb_debug >= 1)
+ fprintf(stderr, "couldn't allocate memory for config extra descriptors\n");
+ config->extralen = 0;
+ return -1;
+ }
+
+ memcpy(config->extra, begin, len);
+ config->extralen = len;
+ }
+ }
+
+ retval = usb_parse_interface(config->interface + i, buffer, size);
+ if (retval < 0)
+ return retval;
+
+ buffer += retval;
+ size -= retval;
+ }
+
+ return size;
+}
+
+void usb_destroy_configuration(struct usb_device *dev)
+{
+ int c, i, j, k;
+
+ if (!dev->config)
+ return;
+
+ for (c = 0; c < dev->descriptor.bNumConfigurations; c++) {
+ struct usb_config_descriptor *cf = &dev->config[c];
+
+ if (!cf->interface)
+ continue;
+
+ for (i = 0; i < cf->bNumInterfaces; i++) {
+ struct usb_interface *ifp = &cf->interface[i];
+
+ if (!ifp->altsetting)
+ continue;
+
+ for (j = 0; j < ifp->num_altsetting; j++) {
+ struct usb_interface_descriptor *as = &ifp->altsetting[j];
+
+ if (as->extra)
+ free(as->extra);
+
+ if (!as->endpoint)
+ continue;
+
+ for (k = 0; k < as->bNumEndpoints; k++) {
+ if (as->endpoint[k].extra)
+ free(as->endpoint[k].extra);
+ }
+ free(as->endpoint);
+ }
+
+ free(ifp->altsetting);
+ }
+
+ free(cf->interface);
+ }
+
+ free(dev->config);
+}
+
+void usb_fetch_and_parse_descriptors(usb_dev_handle *udev)
+{
+ struct usb_device *dev = udev->device;
+ int i;
+
+ if (dev->descriptor.bNumConfigurations > USB_MAXCONFIG) {
+ if (usb_debug >= 1)
+ fprintf(stderr, "Too many configurations (%d > %d)\n", dev->descriptor.bNumConfigurations, USB_MAXCONFIG);
+ return;
+ }
+
+ if (dev->descriptor.bNumConfigurations < 1) {
+ if (usb_debug >= 1)
+ fprintf(stderr, "Not enough configurations (%d < %d)\n", dev->descriptor.bNumConfigurations, 1);
+ return;
+ }
+
+ dev->config = (struct usb_config_descriptor *)malloc(dev->descriptor.bNumConfigurations * sizeof(struct usb_config_descriptor));
+ if (!dev->config) {
+ if (usb_debug >= 1)
+ fprintf(stderr, "Unable to allocate memory for config descriptor\n");
+ return;
+ }
+
+ memset(dev->config, 0, dev->descriptor.bNumConfigurations *
+ sizeof(struct usb_config_descriptor));
+
+ for (i = 0; i < dev->descriptor.bNumConfigurations; i++) {
+ unsigned char buffer[8], *bigbuffer;
+ struct usb_config_descriptor config;
+ int res;
+
+ /* Get the first 8 bytes so we can figure out what the total length is */
+ res = usb_get_descriptor(udev, USB_DT_CONFIG, i, buffer, 8);
+ if (res < 8) {
+ if (usb_debug >= 1) {
+ if (res < 0)
+ fprintf(stderr, "Unable to get descriptor (%d)\n", res);
+ else
+ fprintf(stderr, "Config descriptor too short (expected %d, got %d)\n", 8, res);
+ }
+
+ goto err;
+ }
+
+ usb_parse_descriptor(buffer, "bbw", &config);
+
+ bigbuffer = malloc(config.wTotalLength);
+ if (!bigbuffer) {
+ if (usb_debug >= 1)
+ fprintf(stderr, "Unable to allocate memory for descriptors\n");
+ goto err;
+ }
+
+ res = usb_get_descriptor(udev, USB_DT_CONFIG, i, bigbuffer, config.wTotalLength);
+ if (res < config.wTotalLength) {
+ if (usb_debug >= 1) {
+ if (res < 0)
+ fprintf(stderr, "Unable to get descriptor (%d)\n", res);
+ else
+ fprintf(stderr, "Config descriptor too short (expected %d, got %d)\n", config.wTotalLength, res);
+ }
+
+ free(bigbuffer);
+ goto err;
+ }
+
+ res = usb_parse_configuration(&dev->config[i], bigbuffer);
+ if (usb_debug >= 2) {
+ if (res > 0)
+ fprintf(stderr, "Descriptor data still left\n");
+ else if (res < 0)
+ fprintf(stderr, "Unable to parse descriptors\n");
+ }
+
+ free(bigbuffer);
+ }
+
+ return;
+
+err:
+ free(dev->config);
+
+ dev->config = NULL;
+}
+
diff --git a/libusb/error.c b/libusb/error.c
new file mode 100644
index 0000000..f7d496d
--- /dev/null
+++ b/libusb/error.c
@@ -0,0 +1,36 @@
+/*
+ * USB Error messages
+ *
+ * Copyright (c) 2000-2001 Johannes Erdfelt <johannes@erdfelt.com>
+ *
+ * This library is covered by the LGPL, read LICENSE for details.
+ */
+
+#include <errno.h>
+#include <string.h>
+
+#include "usb.h"
+#include "error.h"
+
+char usb_error_str[1024] = "";
+int usb_error_errno = 0;
+usb_error_type_t usb_error_type = USB_ERROR_TYPE_NONE;
+
+char *usb_strerror(void)
+{
+ switch (usb_error_type) {
+ case USB_ERROR_TYPE_NONE:
+ return "No error";
+ case USB_ERROR_TYPE_STRING:
+ return usb_error_str;
+ case USB_ERROR_TYPE_ERRNO:
+ if (usb_error_errno > -USB_ERROR_BEGIN)
+ return strerror(usb_error_errno);
+ else
+ /* Any error we don't know falls under here */
+ return "Unknown error";
+ }
+
+ return "Unknown error";
+}
+
diff --git a/libusb/error.h b/libusb/error.h
new file mode 100644
index 0000000..173e6fd
--- /dev/null
+++ b/libusb/error.h
@@ -0,0 +1,31 @@
+#ifndef _ERROR_H_
+#define _ERROR_H_
+
+typedef enum {
+ USB_ERROR_TYPE_NONE = 0,
+ USB_ERROR_TYPE_STRING,
+ USB_ERROR_TYPE_ERRNO,
+} usb_error_type_t;
+
+extern char usb_error_str[1024];
+extern int usb_error_errno;
+extern usb_error_type_t usb_error_type;
+
+#define USB_ERROR(x) \
+ do { \
+ usb_error_type = USB_ERROR_TYPE_ERRNO; \
+ usb_error_errno = x; \
+ return x; \
+ } while (0)
+
+#define USB_ERROR_STR(x, format, args...) \
+ do { \
+ usb_error_type = USB_ERROR_TYPE_STRING; \
+ snprintf(usb_error_str, sizeof(usb_error_str) - 1, format, ## args); \
+ if (usb_debug >= 2) \
+ fprintf(stderr, "USB error: %s\n", usb_error_str); \
+ return x; \
+ } while (0)
+
+#endif /* _ERROR_H_ */
+
diff --git a/libusb/linux.c b/libusb/linux.c
new file mode 100644
index 0000000..3a1ce0c
--- /dev/null
+++ b/libusb/linux.c
@@ -0,0 +1,733 @@
+/*
+ * Linux USB support
+ *
+ * Copyright (c) 2000-2003 Johannes Erdfelt <johannes@erdfelt.com>
+ *
+ * This library is covered by the LGPL, read LICENSE for details.
+ */
+
+#include <stdlib.h> /* getenv, etc */
+#include <unistd.h>
+#include <string.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <sys/time.h>
+#include <dirent.h>
+
+#include "linux.h"
+#include "usbi.h"
+
+static char usb_path[PATH_MAX + 1] = "";
+
+static int device_open(struct usb_device *dev)
+{
+ char filename[PATH_MAX + 1];
+ int fd;
+
+ snprintf(filename, sizeof(filename) - 1, "%s/%s/%s",
+ usb_path, dev->bus->dirname, dev->filename);
+
+ fd = open(filename, O_RDWR);
+ if (fd < 0) {
+ fd = open(filename, O_RDONLY);
+ if (fd < 0)
+ USB_ERROR_STR(-errno, "failed to open %s: %s",
+ filename, strerror(errno));
+ }
+
+ return fd;
+}
+
+int usb_os_open(usb_dev_handle *dev)
+{
+ dev->fd = device_open(dev->device);
+
+ return 0;
+}
+
+int usb_os_close(usb_dev_handle *dev)
+{
+ if (dev->fd < 0)
+ return 0;
+
+ if (close(dev->fd) == -1)
+ /* Failing trying to close a file really isn't an error, so return 0 */
+ USB_ERROR_STR(0, "tried to close device fd %d: %s", dev->fd,
+ strerror(errno));
+
+ return 0;
+}
+
+int usb_set_configuration(usb_dev_handle *dev, int configuration)
+{
+ int ret;
+
+ ret = ioctl(dev->fd, IOCTL_USB_SETCONFIG, &configuration);
+ if (ret < 0)
+ USB_ERROR_STR(-errno, "could not set config %d: %s", configuration,
+ strerror(errno));
+
+ dev->config = configuration;
+
+ return 0;
+}
+
+int usb_claim_interface(usb_dev_handle *dev, int interface)
+{
+ int ret;
+
+ ret = ioctl(dev->fd, IOCTL_USB_CLAIMINTF, &interface);
+ if (ret < 0) {
+ if (errno == EBUSY && usb_debug > 0)
+ fprintf(stderr, "Check that you have permissions to write to %s/%s and, if you don't, that you set up hotplug (http://linux-hotplug.sourceforge.net/) correctly.\n", dev->bus->dirname, dev->device->filename);
+
+ USB_ERROR_STR(-errno, "could not claim interface %d: %s", interface,
+ strerror(errno));
+ }
+
+ dev->interface = interface;
+
+ return 0;
+}
+
+int usb_release_interface(usb_dev_handle *dev, int interface)
+{
+ int ret;
+
+ ret = ioctl(dev->fd, IOCTL_USB_RELEASEINTF, &interface);
+ if (ret < 0)
+ USB_ERROR_STR(-errno, "could not release intf %d: %s", interface,
+ strerror(errno));
+
+ dev->interface = -1;
+
+ return 0;
+}
+
+int usb_set_altinterface(usb_dev_handle *dev, int alternate)
+{
+ int ret;
+ struct usb_setinterface setintf;
+
+ if (dev->interface < 0)
+ USB_ERROR(-EINVAL);
+
+ setintf.interface = dev->interface;
+ setintf.altsetting = alternate;
+
+ ret = ioctl(dev->fd, IOCTL_USB_SETINTF, &setintf);
+ if (ret < 0)
+ USB_ERROR_STR(-errno, "could not set alt intf %d/%d: %s",
+ dev->interface, alternate, strerror(errno));
+
+ dev->altsetting = alternate;
+
+ return 0;
+}
+
+/*
+ * Linux usbfs has a limit of one page size for synchronous bulk read/write.
+ * 4096 is the most portable maximum we can do for now.
+ * Linux usbfs has a limit of 16KB for the URB interface. We use this now
+ * to get better performance for USB 2.0 devices.
+ */
+#define MAX_READ_WRITE (16 * 1024)
+
+int usb_control_msg(usb_dev_handle *dev, int requesttype, int request,
+ int value, int index, char *bytes, int size, int timeout)
+{
+ struct usb_ctrltransfer ctrl;
+ int ret;
+
+ ctrl.bRequestType = requesttype;
+ ctrl.bRequest = request;
+ ctrl.wValue = value;
+ ctrl.wIndex = index;
+ ctrl.wLength = size;
+
+ ctrl.data = bytes;
+ ctrl.timeout = timeout;
+
+ ret = ioctl(dev->fd, IOCTL_USB_CONTROL, &ctrl);
+ if (ret < 0)
+ USB_ERROR_STR(-errno, "error sending control message: %s", strerror(errno));
+
+ return ret;
+}
+
+#define URB_USERCONTEXT_COOKIE ((void *)0x1)
+
+/* Reading and writing are the same except for the endpoint */
+static int usb_urb_transfer(usb_dev_handle *dev, int ep, int urbtype,
+ char *bytes, int size, int timeout)
+{
+ struct usb_urb urb;
+ int bytesdone = 0, requested;
+ struct timeval tv, tv_ref, tv_now;
+ struct usb_urb *context;
+ int ret, waiting;
+
+ /*
+ * HACK: The use of urb.usercontext is a hack to get threaded applications
+ * sort of working again. Threaded support is still not recommended, but
+ * this should allow applications to work in the common cases. Basically,
+ * if we get the completion for an URB we're not waiting for, then we update
+ * the usercontext pointer to 1 for the other threads URB and it will see
+ * the change after it wakes up from the the timeout. Ugly, but it works.
+ */
+
+ /*
+ * Get actual time, and add the timeout value. The result is the absolute
+ * time where we have to quit waiting for an message.
+ */
+ gettimeofday(&tv_ref, NULL);
+ tv_ref.tv_sec = tv_ref.tv_sec + timeout / 1000;
+ tv_ref.tv_usec = tv_ref.tv_usec + (timeout % 1000) * 1000;
+
+ if (tv_ref.tv_usec > 1000000) {
+ tv_ref.tv_usec -= 1000000;
+ tv_ref.tv_sec++;
+ }
+
+ do {
+ fd_set writefds;
+
+ requested = size - bytesdone;
+ if (requested > MAX_READ_WRITE)
+ requested = MAX_READ_WRITE;
+
+ urb.type = urbtype;
+ urb.endpoint = ep;
+ urb.flags = 0;
+ urb.buffer = bytes + bytesdone;
+ urb.buffer_length = requested;
+ urb.signr = 0;
+ urb.actual_length = 0;
+ urb.number_of_packets = 0; /* don't do isochronous yet */
+ urb.usercontext = NULL;
+
+ ret = ioctl(dev->fd, IOCTL_USB_SUBMITURB, &urb);
+ if (ret < 0) {
+ USB_ERROR_STR(-errno, "error submitting URB: %s", strerror(errno));
+ return ret;
+ }
+
+ FD_ZERO(&writefds);
+ FD_SET(dev->fd, &writefds);
+
+restart:
+ waiting = 1;
+ context = NULL;
+ while (!urb.usercontext && ((ret = ioctl(dev->fd, IOCTL_USB_REAPURBNDELAY, &context)) == -1) && waiting) {
+ tv.tv_sec = 0;
+ tv.tv_usec = 1000; // 1 msec
+ select(dev->fd + 1, NULL, &writefds, NULL, &tv); //sub second wait
+
+ if (timeout) {
+ /* compare with actual time, as the select timeout is not that precise */
+ gettimeofday(&tv_now, NULL);
+
+ if ((tv_now.tv_sec > tv_ref.tv_sec) ||
+ ((tv_now.tv_sec == tv_ref.tv_sec) && (tv_now.tv_usec >= tv_ref.tv_usec)))
+ waiting = 0;
+ }
+ }
+
+ if (context && context != &urb) {
+ context->usercontext = URB_USERCONTEXT_COOKIE;
+ /* We need to restart since we got a successful URB, but not ours */
+ goto restart;
+ }
+
+ /*
+ * If there was an error, that wasn't EAGAIN (no completion), then
+ * something happened during the reaping and we should return that
+ * error now
+ */
+ if (ret < 0 && !urb.usercontext && errno != EAGAIN)
+ USB_ERROR_STR(-errno, "error reaping URB: %s", strerror(errno));
+
+ bytesdone += urb.actual_length;
+ } while ((ret == 0 || urb.usercontext) && bytesdone < size && urb.actual_length == requested);
+
+ /* If the URB didn't complete in success or error, then let's unlink it */
+ if (ret < 0 && !urb.usercontext) {
+ int rc;
+
+ if (!waiting)
+ rc = -ETIMEDOUT;
+ else
+ rc = urb.status;
+
+ ret = ioctl(dev->fd, IOCTL_USB_DISCARDURB, &urb);
+ if (ret < 0 && errno != EINVAL && usb_debug >= 1)
+ fprintf(stderr, "error discarding URB: %s", strerror(errno));
+
+ /*
+ * When the URB is unlinked, it gets moved to the completed list and
+ * then we need to reap it or else the next time we call this function,
+ * we'll get the previous completion and exit early
+ */
+ ioctl(dev->fd, IOCTL_USB_REAPURB, &context);
+
+ return rc;
+ }
+
+ return bytesdone;
+}
+
+int usb_bulk_write(usb_dev_handle *dev, int ep, char *bytes, int size,
+ int timeout)
+{
+ /* Ensure the endpoint address is correct */
+ return usb_urb_transfer(dev, ep, USB_URB_TYPE_BULK, bytes, size,
+ timeout);
+}
+
+int usb_bulk_read(usb_dev_handle *dev, int ep, char *bytes, int size,
+ int timeout)
+{
+ /* Ensure the endpoint address is correct */
+ ep |= USB_ENDPOINT_IN;
+ return usb_urb_transfer(dev, ep, USB_URB_TYPE_BULK, bytes, size,
+ timeout);
+}
+
+/*
+ * FIXME: Packetize large buffers here. 2.4 HCDs (atleast, haven't checked
+ * 2.5 HCDs yet) don't handle multi-packet Interrupt transfers. So we need
+ * to lookup the endpoint packet size and packetize appropriately here.
+ */
+int usb_interrupt_write(usb_dev_handle *dev, int ep, char *bytes, int size,
+ int timeout)
+{
+ /* Ensure the endpoint address is correct */
+ return usb_urb_transfer(dev, ep, USB_URB_TYPE_INTERRUPT, bytes, size,
+ timeout);
+}
+
+int usb_interrupt_read(usb_dev_handle *dev, int ep, char *bytes, int size,
+ int timeout)
+{
+ /* Ensure the endpoint address is correct */
+ ep |= USB_ENDPOINT_IN;
+ return usb_urb_transfer(dev, ep, USB_URB_TYPE_INTERRUPT, bytes, size,
+ timeout);
+}
+
+int usb_os_find_busses(struct usb_bus **busses)
+{
+ struct usb_bus *fbus = NULL;
+ DIR *dir;
+ struct dirent *entry;
+
+ dir = opendir(usb_path);
+ if (!dir)
+ USB_ERROR_STR(-errno, "couldn't opendir(%s): %s", usb_path,
+ strerror(errno));
+
+ while ((entry = readdir(dir)) != NULL) {
+ struct usb_bus *bus;
+
+ /* Skip anything starting with a . */
+ if (entry->d_name[0] == '.')
+ continue;
+
+ if (!strchr("0123456789", entry->d_name[strlen(entry->d_name) - 1])) {
+ if (usb_debug >= 2)
+ fprintf(stderr, "usb_os_find_busses: Skipping non bus directory %s\n",
+ entry->d_name);
+ continue;
+ }
+
+ bus = malloc(sizeof(*bus));
+ if (!bus)
+ USB_ERROR(-ENOMEM);
+
+ memset((void *)bus, 0, sizeof(*bus));
+
+ strncpy(bus->dirname, entry->d_name, sizeof(bus->dirname) - 1);
+ bus->dirname[sizeof(bus->dirname) - 1] = 0;
+
+ LIST_ADD(fbus, bus);
+
+ if (usb_debug >= 2)
+ fprintf(stderr, "usb_os_find_busses: Found %s\n", bus->dirname);
+ }
+
+ closedir(dir);
+
+ *busses = fbus;
+
+ return 0;
+}
+
+int usb_os_find_devices(struct usb_bus *bus, struct usb_device **devices)
+{
+ struct usb_device *fdev = NULL;
+ DIR *dir;
+ struct dirent *entry;
+ char dirpath[PATH_MAX + 1];
+
+ snprintf(dirpath, PATH_MAX, "%s/%s", usb_path, bus->dirname);
+
+ dir = opendir(dirpath);
+ if (!dir)
+ USB_ERROR_STR(-errno, "couldn't opendir(%s): %s", dirpath,
+ strerror(errno));
+
+ while ((entry = readdir(dir)) != NULL) {
+ unsigned char device_desc[DEVICE_DESC_LENGTH];
+ char filename[PATH_MAX + 1];
+ struct usb_device *dev;
+ struct usb_connectinfo connectinfo;
+ int i, fd, ret;
+
+ /* Skip anything starting with a . */
+ if (entry->d_name[0] == '.')
+ continue;
+
+ dev = malloc(sizeof(*dev));
+ if (!dev)
+ USB_ERROR(-ENOMEM);
+
+ memset((void *)dev, 0, sizeof(*dev));
+
+ dev->bus = bus;
+
+ strncpy(dev->filename, entry->d_name, sizeof(dev->filename) - 1);
+ dev->filename[sizeof(dev->filename) - 1] = 0;
+
+ snprintf(filename, sizeof(filename) - 1, "%s/%s", dirpath, entry->d_name);
+ fd = open(filename, O_RDWR);
+ if (fd < 0) {
+ fd = open(filename, O_RDONLY);
+ if (fd < 0) {
+ if (usb_debug >= 2)
+ fprintf(stderr, "usb_os_find_devices: Couldn't open %s\n",
+ filename);
+
+ free(dev);
+ continue;
+ }
+ }
+
+ /* Get the device number */
+ ret = ioctl(fd, IOCTL_USB_CONNECTINFO, &connectinfo);
+ if (ret < 0) {
+ if (usb_debug)
+ fprintf(stderr, "usb_os_find_devices: couldn't get connect info\n");
+ } else
+ dev->devnum = connectinfo.devnum;
+
+ ret = read(fd, (void *)device_desc, DEVICE_DESC_LENGTH);
+ if (ret < 0) {
+ if (usb_debug)
+ fprintf(stderr, "usb_os_find_devices: Couldn't read descriptor\n");
+
+ free(dev);
+
+ goto err;
+ }
+
+ /*
+ * Linux kernel converts the words in this descriptor to CPU endian, so
+ * we use the undocumented W character for usb_parse_descriptor() that
+ * doesn't convert endianess when parsing the descriptor
+ */
+ usb_parse_descriptor(device_desc, "bbWbbbbWWWbbbb", &dev->descriptor);
+
+ LIST_ADD(fdev, dev);
+
+ if (usb_debug >= 2)
+ fprintf(stderr, "usb_os_find_devices: Found %s on %s\n",
+ dev->filename, bus->dirname);
+
+ /* Now try to fetch the rest of the descriptors */
+ if (dev->descriptor.bNumConfigurations > USB_MAXCONFIG)
+ /* Silent since we'll try again later */
+ goto err;
+
+ if (dev->descriptor.bNumConfigurations < 1)
+ /* Silent since we'll try again later */
+ goto err;
+
+ dev->config = (struct usb_config_descriptor *)malloc(dev->descriptor.bNumConfigurations * sizeof(struct usb_config_descriptor));
+ if (!dev->config)
+ /* Silent since we'll try again later */
+ goto err;
+
+ memset(dev->config, 0, dev->descriptor.bNumConfigurations *
+ sizeof(struct usb_config_descriptor));
+
+ for (i = 0; i < dev->descriptor.bNumConfigurations; i++) {
+ unsigned char buffer[8], *bigbuffer;
+ struct usb_config_descriptor config;
+
+ /* Get the first 8 bytes so we can figure out what the total length is */
+ ret = read(fd, (void *)buffer, 8);
+ if (ret < 8) {
+ if (usb_debug >= 1) {
+ if (ret < 0)
+ fprintf(stderr, "Unable to get descriptor (%d)\n", ret);
+ else
+ fprintf(stderr, "Config descriptor too short (expected %d, got %d)\n", 8, ret);
+ }
+
+ goto err;
+ }
+
+ usb_parse_descriptor(buffer, "bbw", &config);
+
+ bigbuffer = malloc(config.wTotalLength);
+ if (!bigbuffer) {
+ if (usb_debug >= 1)
+ fprintf(stderr, "Unable to allocate memory for descriptors\n");
+ goto err;
+ }
+
+ /* Read the rest of the config descriptor */
+ memcpy(bigbuffer, buffer, 8);
+
+ ret = read(fd, (void *)(bigbuffer + 8), config.wTotalLength - 8);
+ if (ret < config.wTotalLength - 8) {
+ if (usb_debug >= 1) {
+ if (ret < 0)
+ fprintf(stderr, "Unable to get descriptor (%d)\n", ret);
+ else
+ fprintf(stderr, "Config descriptor too short (expected %d, got %d)\n", config.wTotalLength, ret);
+ }
+
+ free(bigbuffer);
+ goto err;
+ }
+
+ ret = usb_parse_configuration(&dev->config[i], bigbuffer);
+ if (usb_debug >= 2) {
+ if (ret > 0)
+ fprintf(stderr, "Descriptor data still left\n");
+ else if (ret < 0)
+ fprintf(stderr, "Unable to parse descriptors\n");
+ }
+
+ free(bigbuffer);
+ }
+
+err:
+ close(fd);
+ }
+
+ closedir(dir);
+
+ *devices = fdev;
+
+ return 0;
+}
+
+int usb_os_determine_children(struct usb_bus *bus)
+{
+ struct usb_device *dev, *devices[256];
+ struct usb_ioctl command;
+ int ret, i, i1;
+
+ /* Create a list of devices first */
+ memset(devices, 0, sizeof(devices));
+ for (dev = bus->devices; dev; dev = dev->next)
+ if (dev->devnum)
+ devices[dev->devnum] = dev;
+
+ /* Now fetch the children for each device */
+ for (dev = bus->devices; dev; dev = dev->next) {
+ struct usb_hub_portinfo portinfo;
+ int fd;
+
+ fd = device_open(dev);
+ if (fd < 0)
+ continue;
+
+ /* Query the hub driver for the children of this device */
+ if (dev->config && dev->config->interface && dev->config->interface->altsetting)
+ command.ifno = dev->config->interface->altsetting->bInterfaceNumber;
+ else
+ command.ifno = 0;
+ command.ioctl_code = IOCTL_USB_HUB_PORTINFO;
+ command.data = &portinfo;
+ ret = ioctl(fd, IOCTL_USB_IOCTL, &command);
+ if (ret < 0) {
+ /* errno == ENOSYS means the device probably wasn't a hub */
+ if (errno != ENOSYS && usb_debug > 1)
+ fprintf(stderr, "error obtaining child information: %s\n",
+ strerror(errno));
+
+ close(fd);
+ continue;
+ }
+
+ dev->num_children = 0;
+ for (i = 0; i < portinfo.numports; i++)
+ if (portinfo.port[i])
+ dev->num_children++;
+
+ /* Free any old children first */
+ free(dev->children);
+
+ dev->children = malloc(sizeof(struct usb_device *) * dev->num_children);
+ if (!dev->children) {
+ if (usb_debug > 1)
+ fprintf(stderr, "error allocating %zu bytes memory for dev->children\n",
+ sizeof(struct usb_device *) * dev->num_children);
+
+ dev->num_children = 0;
+ close(fd);
+ continue;
+ }
+
+ for (i = 0, i1 = 0; i < portinfo.numports; i++) {
+ if (!portinfo.port[i])
+ continue;
+
+ dev->children[i1++] = devices[portinfo.port[i]];
+
+ devices[portinfo.port[i]] = NULL;
+ }
+
+ close(fd);
+ }
+
+ /*
+ * There should be one device left in the devices list and that should be
+ * the root device
+ */
+ for (i = 0; i < sizeof(devices) / sizeof(devices[0]); i++) {
+ if (devices[i])
+ bus->root_dev = devices[i];
+ }
+
+ return 0;
+}
+
+static int check_usb_vfs(const char *dirname)
+{
+ DIR *dir;
+ struct dirent *entry;
+ int found = 0;
+
+ dir = opendir(dirname);
+ if (!dir)
+ return 0;
+
+ while ((entry = readdir(dir)) != NULL) {
+ /* Skip anything starting with a . */
+ if (entry->d_name[0] == '.')
+ continue;
+
+ /* We assume if we find any files that it must be the right place */
+ found = 1;
+ break;
+ }
+
+ closedir(dir);
+
+ return found;
+}
+
+void usb_os_init(void)
+{
+ /* Find the path to the virtual filesystem */
+ if (getenv("USB_DEVFS_PATH")) {
+ if (check_usb_vfs(getenv("USB_DEVFS_PATH"))) {
+ strncpy(usb_path, getenv("USB_DEVFS_PATH"), sizeof(usb_path) - 1);
+ usb_path[sizeof(usb_path) - 1] = 0;
+ } else if (usb_debug)
+ fprintf(stderr, "usb_os_init: couldn't find USB VFS in USB_DEVFS_PATH\n");
+ }
+
+ if (!usb_path[0]) {
+ if (check_usb_vfs("/dev/bus/usb")) {
+ strncpy(usb_path, "/dev/bus/usb", sizeof(usb_path) - 1);
+ usb_path[sizeof(usb_path) - 1] = 0;
+ } else if (check_usb_vfs("/proc/bus/usb")) {
+ strncpy(usb_path, "/proc/bus/usb", sizeof(usb_path) - 1);
+ usb_path[sizeof(usb_path) - 1] = 0;
+ } else
+ usb_path[0] = 0; /* No path, no USB support */
+ }
+
+ if (usb_debug) {
+ if (usb_path[0])
+ fprintf(stderr, "usb_os_init: Found USB VFS at %s\n", usb_path);
+ else
+ fprintf(stderr, "usb_os_init: No USB VFS found, is it mounted?\n");
+ }
+}
+
+int usb_resetep(usb_dev_handle *dev, unsigned int ep)
+{
+ int ret;
+
+ ret = ioctl(dev->fd, IOCTL_USB_RESETEP, &ep);
+ if (ret)
+ USB_ERROR_STR(-errno, "could not reset ep %d: %s", ep,
+ strerror(errno));
+
+ return 0;
+}
+
+int usb_clear_halt(usb_dev_handle *dev, unsigned int ep)
+{
+ int ret;
+
+ ret = ioctl(dev->fd, IOCTL_USB_CLEAR_HALT, &ep);
+ if (ret)
+ USB_ERROR_STR(-errno, "could not clear/halt ep %d: %s", ep,
+ strerror(errno));
+
+ return 0;
+}
+
+int usb_reset(usb_dev_handle *dev)
+{
+ int ret;
+
+ ret = ioctl(dev->fd, IOCTL_USB_RESET, NULL);
+ if (ret)
+ USB_ERROR_STR(-errno, "could not reset: %s", strerror(errno));
+
+ return 0;
+}
+
+int usb_get_driver_np(usb_dev_handle *dev, int interface, char *name,
+ unsigned int namelen)
+{
+ struct usb_getdriver getdrv;
+ int ret;
+
+ getdrv.interface = interface;
+ ret = ioctl(dev->fd, IOCTL_USB_GETDRIVER, &getdrv);
+ if (ret)
+ USB_ERROR_STR(-errno, "could not get bound driver: %s", strerror(errno));
+
+ strncpy(name, getdrv.driver, namelen - 1);
+ name[namelen - 1] = 0;
+
+ return 0;
+}
+
+int usb_detach_kernel_driver_np(usb_dev_handle *dev, int interface)
+{
+ struct usb_ioctl command;
+ int ret;
+
+ command.ifno = interface;
+ command.ioctl_code = IOCTL_USB_DISCONNECT;
+ command.data = NULL;
+
+ ret = ioctl(dev->fd, IOCTL_USB_IOCTL, &command);
+ if (ret)
+ USB_ERROR_STR(-errno, "could not detach kernel driver from interface %d: %s",
+ interface, strerror(errno));
+
+ return 0;
+}
+
diff --git a/libusb/linux.h b/libusb/linux.h
new file mode 100644
index 0000000..8f20ef3
--- /dev/null
+++ b/libusb/linux.h
@@ -0,0 +1,119 @@
+#ifndef __LINUX_H__
+#define __LINUX_H__
+
+#include <unistd.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+
+struct usb_ctrltransfer {
+ /* keep in sync with usbdevice_fs.h:usbdevfs_ctrltransfer */
+ u_int8_t bRequestType;
+ u_int8_t bRequest;
+ u_int16_t wValue;
+ u_int16_t wIndex;
+ u_int16_t wLength;
+
+ u_int32_t timeout; /* in milliseconds */
+
+ /* pointer to data */
+ void *data;
+};
+
+struct usb_bulktransfer {
+ /* keep in sync with usbdevice_fs.h:usbdevfs_bulktransfer */
+ unsigned int ep;
+ unsigned int len;
+ unsigned int timeout; /* in milliseconds */
+
+ /* pointer to data */
+ void *data;
+};
+
+struct usb_setinterface {
+ /* keep in sync with usbdevice_fs.h:usbdevfs_setinterface */
+ unsigned int interface;
+ unsigned int altsetting;
+};
+
+#define USB_MAXDRIVERNAME 255
+
+struct usb_getdriver {
+ unsigned int interface;
+ char driver[USB_MAXDRIVERNAME + 1];
+};
+
+#define USB_URB_DISABLE_SPD 1
+#define USB_URB_ISO_ASAP 2
+#define USB_URB_QUEUE_BULK 0x10
+
+#define USB_URB_TYPE_ISO 0
+#define USB_URB_TYPE_INTERRUPT 1
+#define USB_URB_TYPE_CONTROL 2
+#define USB_URB_TYPE_BULK 3
+
+struct usb_iso_packet_desc {
+ unsigned int length;
+ unsigned int actual_length;
+ unsigned int status;
+};
+
+struct usb_urb {
+ unsigned char type;
+ unsigned char endpoint;
+ int status;
+ unsigned int flags;
+ void *buffer;
+ int buffer_length;
+ int actual_length;
+ int start_frame;
+ int number_of_packets;
+ int error_count;
+ unsigned int signr; /* signal to be sent on error, -1 if none should be sent */
+ void *usercontext;
+ struct usb_iso_packet_desc iso_frame_desc[0];
+};
+
+struct usb_connectinfo {
+ unsigned int devnum;
+ unsigned char slow;
+};
+
+struct usb_ioctl {
+ int ifno; /* interface 0..N ; negative numbers reserved */
+ int ioctl_code; /* MUST encode size + direction of data so the
+ * macros in <asm/ioctl.h> give correct values */
+ void *data; /* param buffer (in, or out) */
+};
+
+struct usb_hub_portinfo {
+ unsigned char numports;
+ unsigned char port[127]; /* port to device num mapping */
+};
+
+#define IOCTL_USB_CONTROL _IOWR('U', 0, struct usb_ctrltransfer)
+#define IOCTL_USB_BULK _IOWR('U', 2, struct usb_bulktransfer)
+#define IOCTL_USB_RESETEP _IOR('U', 3, unsigned int)
+#define IOCTL_USB_SETINTF _IOR('U', 4, struct usb_setinterface)
+#define IOCTL_USB_SETCONFIG _IOR('U', 5, unsigned int)
+#define IOCTL_USB_GETDRIVER _IOW('U', 8, struct usb_getdriver)
+#define IOCTL_USB_SUBMITURB _IOR('U', 10, struct usb_urb)
+#define IOCTL_USB_DISCARDURB _IO('U', 11)
+#define IOCTL_USB_REAPURB _IOW('U', 12, void *)
+#define IOCTL_USB_REAPURBNDELAY _IOW('U', 13, void *)
+#define IOCTL_USB_CLAIMINTF _IOR('U', 15, unsigned int)
+#define IOCTL_USB_RELEASEINTF _IOR('U', 16, unsigned int)
+#define IOCTL_USB_CONNECTINFO _IOW('U', 17, struct usb_connectinfo)
+#define IOCTL_USB_IOCTL _IOWR('U', 18, struct usb_ioctl)
+#define IOCTL_USB_HUB_PORTINFO _IOR('U', 19, struct usb_hub_portinfo)
+#define IOCTL_USB_RESET _IO('U', 20)
+#define IOCTL_USB_CLEAR_HALT _IOR('U', 21, unsigned int)
+#define IOCTL_USB_DISCONNECT _IO('U', 22)
+#define IOCTL_USB_CONNECT _IO('U', 23)
+
+/*
+ * IOCTL_USB_HUB_PORTINFO, IOCTL_USB_DISCONNECT and IOCTL_USB_CONNECT
+ * all work via IOCTL_USB_IOCTL
+ */
+
+#endif
+
diff --git a/libusb/usb.c b/libusb/usb.c
new file mode 100644
index 0000000..9b8773e
--- /dev/null
+++ b/libusb/usb.c
@@ -0,0 +1,307 @@
+/*
+ * Main API entry point
+ *
+ * Copyright (c) 2000-2003 Johannes Erdfelt <johannes@erdfelt.com>
+ *
+ * This library is covered by the LGPL, read LICENSE for details.
+ */
+
+#include <stdlib.h> /* getenv */
+#include <stdio.h> /* stderr */
+#include <string.h> /* strcmp */
+#include <errno.h>
+
+#include "usbi.h"
+
+int usb_debug = 0;
+struct usb_bus *usb_busses = NULL;
+
+int usb_find_busses(void)
+{
+ struct usb_bus *busses, *bus;
+ int ret, changes = 0;
+
+ ret = usb_os_find_busses(&busses);
+ if (ret < 0)
+ return ret;
+
+ /*
+ * Now walk through all of the busses we know about and compare against
+ * this new list. Any duplicates will be removed from the new list.
+ * If we don't find it in the new list, the bus was removed. Any
+ * busses still in the new list, are new to us.
+ */
+ bus = usb_busses;
+ while (bus) {
+ int found = 0;
+ struct usb_bus *nbus, *tbus = bus->next;
+
+ nbus = busses;
+ while (nbus) {
+ struct usb_bus *tnbus = nbus->next;
+
+ if (!strcmp(bus->dirname, nbus->dirname)) {
+ /* Remove it from the new busses list */
+ LIST_DEL(busses, nbus);
+
+ usb_free_bus(nbus);
+ found = 1;
+ break;
+ }
+
+ nbus = tnbus;
+ }
+
+ if (!found) {
+ /* The bus was removed from the system */
+ LIST_DEL(usb_busses, bus);
+ usb_free_bus(bus);
+ changes++;
+ }
+
+ bus = tbus;
+ }
+
+ /*
+ * Anything on the *busses list is new. So add them to usb_busses and
+ * process them like the new bus it is.
+ */
+ bus = busses;
+ while (bus) {
+ struct usb_bus *tbus = bus->next;
+
+ /*
+ * Remove it from the temporary list first and add it to the real
+ * usb_busses list.
+ */
+ LIST_DEL(busses, bus);
+
+ LIST_ADD(usb_busses, bus);
+
+ changes++;
+
+ bus = tbus;
+ }
+
+ return changes;
+}
+
+int usb_find_devices(void)
+{
+ struct usb_bus *bus;
+ int ret, changes = 0;
+
+ for (bus = usb_busses; bus; bus = bus->next) {
+ struct usb_device *devices, *dev;
+
+ /* Find all of the devices and put them into a temporary list */
+ ret = usb_os_find_devices(bus, &devices);
+ if (ret < 0)
+ return ret;
+
+ /*
+ * Now walk through all of the devices we know about and compare
+ * against this new list. Any duplicates will be removed from the new
+ * list. If we don't find it in the new list, the device was removed.
+ * Any devices still in the new list, are new to us.
+ */
+ dev = bus->devices;
+ while (dev) {
+ int found = 0;
+ struct usb_device *ndev, *tdev = dev->next;
+
+ ndev = devices;
+ while (ndev) {
+ struct usb_device *tndev = ndev->next;
+
+ if (!strcmp(dev->filename, ndev->filename)) {
+ /* Remove it from the new devices list */
+ LIST_DEL(devices, ndev);
+
+ usb_free_dev(ndev);
+ found = 1;
+ break;
+ }
+
+ ndev = tndev;
+ }
+
+ if (!found) {
+ /* The device was removed from the system */
+ LIST_DEL(bus->devices, dev);
+ usb_free_dev(dev);
+ changes++;
+ }
+
+ dev = tdev;
+ }
+
+ /*
+ * Anything on the *devices list is new. So add them to bus->devices and
+ * process them like the new device it is.
+ */
+ dev = devices;
+ while (dev) {
+ struct usb_device *tdev = dev->next;
+
+ /*
+ * Remove it from the temporary list first and add it to the real
+ * bus->devices list.
+ */
+ LIST_DEL(devices, dev);
+
+ LIST_ADD(bus->devices, dev);
+
+ /*
+ * Some ports fetch the descriptors on scanning (like Linux) so we don't
+ * need to fetch them again.
+ */
+ if (!dev->config) {
+ usb_dev_handle *udev;
+
+ udev = usb_open(dev);
+ if (udev) {
+ usb_fetch_and_parse_descriptors(udev);
+
+ usb_close(udev);
+ }
+ }
+
+ changes++;
+
+ dev = tdev;
+ }
+
+ usb_os_determine_children(bus);
+ }
+
+ return changes;
+}
+
+void usb_set_debug(int level)
+{
+ if (usb_debug || level)
+ fprintf(stderr, "usb_set_debug: Setting debugging level to %d (%s)\n",
+ level, level ? "on" : "off");
+
+ usb_debug = level;
+}
+
+void usb_init(void)
+{
+ if (getenv("USB_DEBUG"))
+ usb_set_debug(atoi(getenv("USB_DEBUG")));
+
+ usb_os_init();
+}
+
+usb_dev_handle *usb_open(struct usb_device *dev)
+{
+ usb_dev_handle *udev;
+
+ udev = malloc(sizeof(*udev));
+ if (!udev)
+ return NULL;
+
+ udev->fd = -1;
+ udev->device = dev;
+ udev->bus = dev->bus;
+ udev->config = udev->interface = udev->altsetting = -1;
+
+ if (usb_os_open(udev) < 0) {
+ free(udev);
+ return NULL;
+ }
+
+ return udev;
+}
+
+int usb_get_string(usb_dev_handle *dev, int index, int langid, char *buf,
+ size_t buflen)
+{
+ /*
+ * We can't use usb_get_descriptor() because it's lacking the index
+ * parameter. This will be fixed in libusb 1.0
+ */
+ return usb_control_msg(dev, USB_ENDPOINT_IN, USB_REQ_GET_DESCRIPTOR,
+ (USB_DT_STRING << 8) + index, langid, buf, buflen, 1000);
+}
+
+int usb_get_string_simple(usb_dev_handle *dev, int index, char *buf, size_t buflen)
+{
+ char tbuf[255]; /* Some devices choke on size > 255 */
+ int ret, langid, si, di;
+
+ /*
+ * Asking for the zero'th index is special - it returns a string
+ * descriptor that contains all the language IDs supported by the
+ * device. Typically there aren't many - often only one. The
+ * language IDs are 16 bit numbers, and they start at the third byte
+ * in the descriptor. See USB 2.0 specification, section 9.6.7, for
+ * more information on this. */
+ ret = usb_get_string(dev, 0, 0, tbuf, sizeof(tbuf));
+ if (ret < 0)
+ return ret;
+
+ if (ret < 4)
+ return -EIO;
+
+ langid = tbuf[2] | (tbuf[3] << 8);
+
+ ret = usb_get_string(dev, index, langid, tbuf, sizeof(tbuf));
+ if (ret < 0)
+ return ret;
+
+ if (tbuf[1] != USB_DT_STRING)
+ return -EIO;
+
+ if (tbuf[0] > ret)
+ return -EFBIG;
+
+ for (di = 0, si = 2; si < tbuf[0]; si += 2) {
+ if (di >= (buflen - 1))
+ break;
+
+ if (tbuf[si + 1]) /* high byte */
+ buf[di++] = '?';
+ else
+ buf[di++] = tbuf[si];
+ }
+
+ buf[di] = 0;
+
+ return di;
+}
+
+int usb_close(usb_dev_handle *dev)
+{
+ int ret;
+
+ ret = usb_os_close(dev);
+ free(dev);
+
+ return ret;
+}
+
+struct usb_device *usb_device(usb_dev_handle *dev)
+{
+ return dev->device;
+}
+
+void usb_free_dev(struct usb_device *dev)
+{
+ usb_destroy_configuration(dev);
+ free(dev->children);
+ free(dev);
+}
+
+struct usb_bus *usb_get_busses(void)
+{
+ return usb_busses;
+}
+
+void usb_free_bus(struct usb_bus *bus)
+{
+ free(bus);
+}
+
diff --git a/libusb/usb.h b/libusb/usb.h
new file mode 100644
index 0000000..ea3a7e9
--- /dev/null
+++ b/libusb/usb.h
@@ -0,0 +1,337 @@
+/*
+ * Prototypes, structure definitions and macros.
+ *
+ * Copyright (c) 2000-2003 Johannes Erdfelt <johannes@erdfelt.com>
+ *
+ * This library is covered by the LGPL, read LICENSE for details.
+ *
+ * This file (and only this file) may alternatively be licensed under the
+ * BSD license as well, read LICENSE for details.
+ */
+#ifndef __USB_H__
+#define __USB_H__
+
+#include <unistd.h>
+#include <stdlib.h>
+#include <limits.h>
+
+#include <dirent.h>
+
+/*
+ * USB spec information
+ *
+ * This is all stuff grabbed from various USB specs and is pretty much
+ * not subject to change
+ */
+
+/*
+ * Device and/or Interface Class codes
+ */
+#define USB_CLASS_PER_INTERFACE 0 /* for DeviceClass */
+#define USB_CLASS_AUDIO 1
+#define USB_CLASS_COMM 2
+#define USB_CLASS_HID 3
+#define USB_CLASS_PRINTER 7
+#define USB_CLASS_PTP 6
+#define USB_CLASS_MASS_STORAGE 8
+#define USB_CLASS_HUB 9
+#define USB_CLASS_DATA 10
+#define USB_CLASS_VENDOR_SPEC 0xff
+
+/*
+ * Descriptor types
+ */
+#define USB_DT_DEVICE 0x01
+#define USB_DT_CONFIG 0x02
+#define USB_DT_STRING 0x03
+#define USB_DT_INTERFACE 0x04
+#define USB_DT_ENDPOINT 0x05
+
+#define USB_DT_HID 0x21
+#define USB_DT_REPORT 0x22
+#define USB_DT_PHYSICAL 0x23
+#define USB_DT_HUB 0x29
+
+/*
+ * Descriptor sizes per descriptor type
+ */
+#define USB_DT_DEVICE_SIZE 18
+#define USB_DT_CONFIG_SIZE 9
+#define USB_DT_INTERFACE_SIZE 9
+#define USB_DT_ENDPOINT_SIZE 7
+#define USB_DT_ENDPOINT_AUDIO_SIZE 9 /* Audio extension */
+#define USB_DT_HUB_NONVAR_SIZE 7
+
+/* All standard descriptors have these 2 fields in common */
+struct usb_descriptor_header {
+ u_int8_t bLength;
+ u_int8_t bDescriptorType;
+};
+
+/* String descriptor */
+struct usb_string_descriptor {
+ u_int8_t bLength;
+ u_int8_t bDescriptorType;
+ u_int16_t wData[1];
+};
+
+/* HID descriptor */
+struct usb_hid_descriptor {
+ u_int8_t bLength;
+ u_int8_t bDescriptorType;
+ u_int16_t bcdHID;
+ u_int8_t bCountryCode;
+ u_int8_t bNumDescriptors;
+ /* u_int8_t bReportDescriptorType; */
+ /* u_int16_t wDescriptorLength; */
+ /* ... */
+};
+
+/* Endpoint descriptor */
+#define USB_MAXENDPOINTS 32
+struct usb_endpoint_descriptor {
+ u_int8_t bLength;
+ u_int8_t bDescriptorType;
+ u_int8_t bEndpointAddress;
+ u_int8_t bmAttributes;
+ u_int16_t wMaxPacketSize;
+ u_int8_t bInterval;
+ u_int8_t bRefresh;
+ u_int8_t bSynchAddress;
+
+ unsigned char *extra; /* Extra descriptors */
+ int extralen;
+};
+
+#define USB_ENDPOINT_ADDRESS_MASK 0x0f /* in bEndpointAddress */
+#define USB_ENDPOINT_DIR_MASK 0x80
+
+#define USB_ENDPOINT_TYPE_MASK 0x03 /* in bmAttributes */
+#define USB_ENDPOINT_TYPE_CONTROL 0
+#define USB_ENDPOINT_TYPE_ISOCHRONOUS 1
+#define USB_ENDPOINT_TYPE_BULK 2
+#define USB_ENDPOINT_TYPE_INTERRUPT 3
+
+/* Interface descriptor */
+#define USB_MAXINTERFACES 32
+struct usb_interface_descriptor {
+ u_int8_t bLength;
+ u_int8_t bDescriptorType;
+ u_int8_t bInterfaceNumber;
+ u_int8_t bAlternateSetting;
+ u_int8_t bNumEndpoints;
+ u_int8_t bInterfaceClass;
+ u_int8_t bInterfaceSubClass;
+ u_int8_t bInterfaceProtocol;
+ u_int8_t iInterface;
+
+ struct usb_endpoint_descriptor *endpoint;
+
+ unsigned char *extra; /* Extra descriptors */
+ int extralen;
+};
+
+#define USB_MAXALTSETTING 128 /* Hard limit */
+struct usb_interface {
+ struct usb_interface_descriptor *altsetting;
+
+ int num_altsetting;
+};
+
+/* Configuration descriptor information.. */
+#define USB_MAXCONFIG 8
+struct usb_config_descriptor {
+ u_int8_t bLength;
+ u_int8_t bDescriptorType;
+ u_int16_t wTotalLength;
+ u_int8_t bNumInterfaces;
+ u_int8_t bConfigurationValue;
+ u_int8_t iConfiguration;
+ u_int8_t bmAttributes;
+ u_int8_t MaxPower;
+
+ struct usb_interface *interface;
+
+ unsigned char *extra; /* Extra descriptors */
+ int extralen;
+};
+
+/* Device descriptor */
+struct usb_device_descriptor {
+ u_int8_t bLength;
+ u_int8_t bDescriptorType;
+ u_int16_t bcdUSB;
+ u_int8_t bDeviceClass;
+ u_int8_t bDeviceSubClass;
+ u_int8_t bDeviceProtocol;
+ u_int8_t bMaxPacketSize0;
+ u_int16_t idVendor;
+ u_int16_t idProduct;
+ u_int16_t bcdDevice;
+ u_int8_t iManufacturer;
+ u_int8_t iProduct;
+ u_int8_t iSerialNumber;
+ u_int8_t bNumConfigurations;
+};
+
+struct usb_ctrl_setup {
+ u_int8_t bRequestType;
+ u_int8_t bRequest;
+ u_int16_t wValue;
+ u_int16_t wIndex;
+ u_int16_t wLength;
+};
+
+/*
+ * Standard requests
+ */
+#define USB_REQ_GET_STATUS 0x00
+#define USB_REQ_CLEAR_FEATURE 0x01
+/* 0x02 is reserved */
+#define USB_REQ_SET_FEATURE 0x03
+/* 0x04 is reserved */
+#define USB_REQ_SET_ADDRESS 0x05
+#define USB_REQ_GET_DESCRIPTOR 0x06
+#define USB_REQ_SET_DESCRIPTOR 0x07
+#define USB_REQ_GET_CONFIGURATION 0x08
+#define USB_REQ_SET_CONFIGURATION 0x09
+#define USB_REQ_GET_INTERFACE 0x0A
+#define USB_REQ_SET_INTERFACE 0x0B
+#define USB_REQ_SYNCH_FRAME 0x0C
+
+#define USB_TYPE_STANDARD (0x00 << 5)
+#define USB_TYPE_CLASS (0x01 << 5)
+#define USB_TYPE_VENDOR (0x02 << 5)
+#define USB_TYPE_RESERVED (0x03 << 5)
+
+#define USB_RECIP_DEVICE 0x00
+#define USB_RECIP_INTERFACE 0x01
+#define USB_RECIP_ENDPOINT 0x02
+#define USB_RECIP_OTHER 0x03
+
+/*
+ * Various libusb API related stuff
+ */
+
+#define USB_ENDPOINT_IN 0x80
+#define USB_ENDPOINT_OUT 0x00
+
+/* Error codes */
+#define USB_ERROR_BEGIN 500000
+
+/*
+ * This is supposed to look weird. This file is generated from autoconf
+ * and I didn't want to make this too complicated.
+ */
+#if 0
+#define USB_LE16_TO_CPU(x) do { x = ((x & 0xff) << 8) | ((x & 0xff00) >> 8); } while(0)
+#else
+#define USB_LE16_TO_CPU(x)
+#endif
+
+/* Data types */
+struct usb_device;
+struct usb_bus;
+
+/*
+ * To maintain compatibility with applications already built with libusb,
+ * we must only add entries to the end of this structure. NEVER delete or
+ * move members and only change types if you really know what you're doing.
+ */
+struct usb_device {
+ struct usb_device *next, *prev;
+
+ char filename[PATH_MAX + 1];
+
+ struct usb_bus *bus;
+
+ struct usb_device_descriptor descriptor;
+ struct usb_config_descriptor *config;
+
+ void *dev; /* Darwin support */
+
+ u_int8_t devnum;
+
+ unsigned char num_children;
+ struct usb_device **children;
+};
+
+struct usb_bus {
+ struct usb_bus *next, *prev;
+
+ char dirname[PATH_MAX + 1];
+
+ struct usb_device *devices;
+ u_int32_t location;
+
+ struct usb_device *root_dev;
+};
+
+struct usb_dev_handle;
+typedef struct usb_dev_handle usb_dev_handle;
+
+/* Variables */
+extern struct usb_bus *usb_busses;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Function prototypes */
+
+/* usb.c */
+usb_dev_handle *usb_open(struct usb_device *dev);
+int usb_close(usb_dev_handle *dev);
+int usb_get_string(usb_dev_handle *dev, int index, int langid, char *buf,
+ size_t buflen);
+int usb_get_string_simple(usb_dev_handle *dev, int index, char *buf,
+ size_t buflen);
+
+/* descriptors.c */
+int usb_get_descriptor_by_endpoint(usb_dev_handle *udev, int ep,
+ unsigned char type, unsigned char index, void *buf, int size);
+int usb_get_descriptor(usb_dev_handle *udev, unsigned char type,
+ unsigned char index, void *buf, int size);
+
+/* <arch>.c */
+int usb_bulk_write(usb_dev_handle *dev, int ep, char *bytes, int size,
+ int timeout);
+int usb_bulk_read(usb_dev_handle *dev, int ep, char *bytes, int size,
+ int timeout);
+int usb_interrupt_write(usb_dev_handle *dev, int ep, char *bytes, int size,
+ int timeout);
+int usb_interrupt_read(usb_dev_handle *dev, int ep, char *bytes, int size,
+ int timeout);
+int usb_control_msg(usb_dev_handle *dev, int requesttype, int request,
+ int value, int index, char *bytes, int size, int timeout);
+int usb_set_configuration(usb_dev_handle *dev, int configuration);
+int usb_claim_interface(usb_dev_handle *dev, int interface);
+int usb_release_interface(usb_dev_handle *dev, int interface);
+int usb_set_altinterface(usb_dev_handle *dev, int alternate);
+int usb_resetep(usb_dev_handle *dev, unsigned int ep);
+int usb_clear_halt(usb_dev_handle *dev, unsigned int ep);
+int usb_reset(usb_dev_handle *dev);
+
+#if 1
+#define LIBUSB_HAS_GET_DRIVER_NP 1
+int usb_get_driver_np(usb_dev_handle *dev, int interface, char *name,
+ unsigned int namelen);
+#define LIBUSB_HAS_DETACH_KERNEL_DRIVER_NP 1
+int usb_detach_kernel_driver_np(usb_dev_handle *dev, int interface);
+#endif
+
+char *usb_strerror(void);
+
+void usb_init(void);
+void usb_set_debug(int level);
+int usb_find_busses(void);
+int usb_find_devices(void);
+struct usb_device *usb_device(usb_dev_handle *dev);
+struct usb_bus *usb_get_busses(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __USB_H__ */
+
diff --git a/libusb/usbi.h b/libusb/usbi.h
new file mode 100644
index 0000000..5fe8c8e
--- /dev/null
+++ b/libusb/usbi.h
@@ -0,0 +1,74 @@
+#ifndef _USBI_H_
+#define _USBI_H_
+
+#include "usb.h"
+
+#include "error.h"
+
+extern int usb_debug;
+
+/* Some quick and generic macros for the simple kind of lists we use */
+#define LIST_ADD(begin, ent) \
+ do { \
+ if (begin) { \
+ ent->next = begin; \
+ ent->next->prev = ent; \
+ } else \
+ ent->next = NULL; \
+ ent->prev = NULL; \
+ begin = ent; \
+ } while(0)
+
+#define LIST_DEL(begin, ent) \
+ do { \
+ if (ent->prev) \
+ ent->prev->next = ent->next; \
+ else \
+ begin = ent->next; \
+ if (ent->next) \
+ ent->next->prev = ent->prev; \
+ ent->prev = NULL; \
+ ent->next = NULL; \
+ } while (0)
+
+#define DESC_HEADER_LENGTH 2
+#define DEVICE_DESC_LENGTH 18
+#define CONFIG_DESC_LENGTH 9
+#define INTERFACE_DESC_LENGTH 9
+#define ENDPOINT_DESC_LENGTH 7
+#define ENDPOINT_AUDIO_DESC_LENGTH 9
+
+struct usb_dev_handle {
+ int fd;
+
+ struct usb_bus *bus;
+ struct usb_device *device;
+
+ int config;
+ int interface;
+ int altsetting;
+
+ /* Added by RMT so implementations can store other per-open-device data */
+ void *impl_info;
+};
+
+/* descriptors.c */
+int usb_parse_descriptor(unsigned char *source, char *description, void *dest);
+int usb_parse_configuration(struct usb_config_descriptor *config,
+ unsigned char *buffer);
+void usb_fetch_and_parse_descriptors(usb_dev_handle *udev);
+void usb_destroy_configuration(struct usb_device *dev);
+
+/* OS specific routines */
+int usb_os_find_busses(struct usb_bus **busses);
+int usb_os_find_devices(struct usb_bus *bus, struct usb_device **devices);
+int usb_os_determine_children(struct usb_bus *bus);
+void usb_os_init(void);
+int usb_os_open(usb_dev_handle *dev);
+int usb_os_close(usb_dev_handle *dev);
+
+void usb_free_dev(struct usb_device *dev);
+void usb_free_bus(struct usb_bus *bus);
+
+#endif /* _USBI_H_ */
+
diff --git a/libusb/usbpp.h b/libusb/usbpp.h
new file mode 100644
index 0000000..abda64f
--- /dev/null
+++ b/libusb/usbpp.h
@@ -0,0 +1,855 @@
+// -*- C++;indent-tabs-mode: t; tab-width: 4; c-basic-offset: 4; -*-
+#ifndef __USBPP_HEADER__
+#define __USBPP_HEADER__
+
+#include <string>
+#include <list>
+
+#include <usb.h>
+
+/*
+ * The following usb.h function is not wrapped yet:
+ * char *usb_strerror(void);
+ */
+
+
+/**
+ * \brief Classes to access Universal Serial Bus devices
+ *
+ * The USB Namespace provides a number of classes to work
+ * with Universal Serial Bus (USB) devices attached to the
+ * system.
+ *
+ * \author Brad Hards
+ */
+namespace USB {
+
+ class Device;
+
+ /**
+ * \brief Class representing a device endpoint
+ *
+ * This class represents a device endpoint. You need this class to
+ * perform bulk reads and writes.
+ *
+ */
+ class Endpoint {
+ /**
+ * Busses is a friend because it fills in the descriptor type
+ * information on initialisation and rescan.
+ */
+ friend class Busses;
+ public:
+ Endpoint() {};
+
+#ifdef USE_UNTESTED_LIBUSBPP_METHODS
+ /**
+ * \brief Bulk write
+ *
+ * This method performs a bulk transfer to the endpoint.
+ *
+ * \param message is the message to be sent.
+ * \param timeout is the USB transaction timeout in milliseconds
+ *
+ * \returns the number of bytes sent, or a negative value on
+ * failure
+ */
+ int bulkWrite(QByteArray message, int timeout = 100);
+
+ /**
+ * \brief Bulk read
+ *
+ * This method performs a bulk transfer from the endpoint.
+ *
+ * \param length is the maximum data transfer required.
+ * \param message is the message that was received.
+ * \param timeout is the USB transaction timeout in milliseconds
+ *
+ * \returns the number of bytes received, or a negative value on
+ * failure
+ */
+ int bulkRead(int length, unsigned char *message, int timeout = 100);
+
+ /**
+ * \brief Reset endpoint
+ *
+ * This method resets the endpoint.
+ */
+ int reset(void);
+
+ /**
+ * \brief Clear halt
+ *
+ * This method clears a halt (stall) on the endpoint.
+ */
+ int clearHalt(void);
+
+#endif /* USE_UNTESTED_LIBUSBPP_METHODS */
+
+ /**
+ * \brief Endpoint descriptor information output
+ *
+ * This method dumps out the various characteristics
+ * of the endpoint to standard output.
+ *
+ * It is mostly useful for debugging.
+ */
+ void dumpDescriptor(void);
+
+ private:
+ void setDescriptor(struct usb_endpoint_descriptor);
+ void setParent(Device *parent);
+ u_int8_t m_Length;
+ u_int8_t m_DescriptorType;
+ u_int8_t m_EndpointAddress;
+ u_int8_t m_Attributes;
+ u_int16_t m_MaxPacketSize;
+ u_int8_t m_Interval;
+ u_int8_t m_Refresh;
+ u_int8_t m_SynchAddress;
+ Device *m_parent;
+ };
+
+ class AltSetting : public std::list<Endpoint *> {
+ /**
+ * Busses is a friend because it fills in the descriptor type
+ * information on initialisation and rescan.
+ */
+ friend class Busses;
+ public:
+ AltSetting() {};
+ u_int8_t numEndpoints(void);
+
+ /**
+ * \brief AltSetting descriptor information output
+ *
+ * This method dumps out the various characteristics
+ * of the alternate setting to standard output.
+ *
+ * It is mostly useful for debugging.
+ */
+ void dumpDescriptor(void);
+
+ Endpoint *firstEndpoint(void);
+ Endpoint *nextEndpoint(void);
+ Endpoint *lastEndpoint(void);
+
+ private:
+ std::list<Endpoint *>::const_iterator iter;
+
+ void setDescriptor(struct usb_interface_descriptor);
+ /* we don't use a normal usb_interface_descriptor */
+ /* because that would bring in the endpoint list */
+ u_int8_t m_Length;
+ u_int8_t m_DescriptorType;
+ u_int8_t m_InterfaceNumber;
+ u_int8_t m_AlternateSetting;
+ u_int8_t m_NumEndpoints;
+ u_int8_t m_InterfaceClass;
+ u_int8_t m_InterfaceSubClass;
+ u_int8_t m_InterfaceProtocol;
+ u_int8_t m_Interface;
+ };
+
+ /**
+ * \brief Class representing an interface of a Device
+ *
+ * The Interface class represents a USB interface
+ * for a device attached to a Universal Serial Bus.
+ *
+ * Interfaces are the main element of the USB class
+ * structure.
+ *
+ * \author Brad Hards
+ */
+ class Interface : public std::list<AltSetting *> {
+ /**
+ * Busses is a friend because it fills in the descriptor type
+ * information on initialisation and rescan.
+ */
+ friend class Busses;
+ public:
+ Interface() {};
+
+#ifdef LIBUSB_HAS_GET_DRIVER_NP
+ /**
+ * \brief get the current driver for an interface
+ *
+ * \param driver a string containing the name of the current
+ * driver for the interface. You can typically pass in an empty
+ * string for this.
+ *
+ * \return length of string, or 0 on error.
+ */
+ int driverName(std::string &driver);
+#endif
+
+#ifdef USE_UNTESTED_LIBUSBPP_METHODS
+ /**
+ * \brief Claim this interface
+ *
+ * This method claims the interface. You have to claim the
+ * interface before performing any operations on the interface (or
+ * on endpoints that are part of the interface).
+ *
+ * \return 0 on success or negative number on error.
+ */
+ int claim(void);
+
+ /**
+ * \brief Release this interface
+ *
+ * This method releases the interface. You should release the
+ * interface after all operations on it (and any lower level
+ * endpoints) are completed.
+ *
+ * \return 0 on success or negative number on error.
+ */
+ int release(void);
+
+ /**
+ * \brief Set interface alternate setting
+ *
+ * This method sets the interface to a particular AltSetting.
+ *
+ * \param altSettingNumber the AltSetting that the interface
+ * should be changed to.
+ *
+ * \return 0 on success, or a negative number in case of error.
+ */
+ int setAltSetting(int altSettingNumber);
+#endif /* USE_UNTESTED_LIBUSBPP_METHODS */
+
+ /**
+ * \brief Number of Alternative Settings that this interface has
+ *
+ * This is a simple accessor method that specifies the number
+ * alternative settings that this device interface has.
+ */
+ u_int8_t numAltSettings(void);
+
+ /**
+ * \brief First AltSetting for the Interface
+ *
+ * This method returns a pointer to the first AltSetting
+ * for the Interface.
+ *
+ * See nextAltSetting() for an example of how it might be
+ * used.
+ *
+ * \see nextAltSetting(), lastAltSetting(), numAltSettings()
+ */
+ AltSetting *firstAltSetting(void);
+
+ /**
+ * \brief Next AltSetting for the Interface
+ *
+ * This method returns a pointer to the next AltSetting
+ * for the Interface.
+ *
+ * If you want to iterate through each AltSetting on
+ * a device, you can use something like the following:
+ * \code
+ * USB::Configuration *this_Configuration;
+ * this_Configuration = device->firstConfiguration();
+ * for (i=0; i < device->numConfigurations(); i++) {
+ * this_Configuration->dumpDescriptor();
+ * USB::Interface *this_Interface;
+ * this_Interface = this_Configuration->firstInterface();
+ * for (j=0; j < this_Configuration->numInterfaces(); j++) {
+ * USB::AltSetting *this_AltSetting;
+ * this_AltSetting = this_Interface->firstAltSetting();
+ * for (k=0; k < this_Interface->numAltSettings(); k++) {
+ * // do something with this_AltSetting
+ * this_AltSetting = this_Interface->nextAltSetting();
+ * }
+ * this_Interface = this_Configuration->nextInterface();
+ * }
+ * this_Configuration = device->nextConfiguration();
+ * }
+ * \endcode
+ *
+ * \see firstAltSetting(), lastAltSetting(), numAltSettings()
+ */
+ AltSetting *nextAltSetting(void);
+
+ /**
+ * \brief Last AltSetting for the Interface
+ *
+ * This method returns a pointer to the last AltSetting
+ * for the Interface.
+ *
+ * \see firstAltSetting(), nextAltSetting(), numAltSettings()
+ */
+
+ AltSetting *lastAltSetting(void);
+
+ private:
+ std::list<AltSetting *>::const_iterator iter;
+
+ void setNumAltSettings(u_int8_t);
+ void setParent(Device *parent);
+ u_int8_t m_numAltSettings;
+ Device *m_parent;
+
+ /* index representing the interface, in this configuration */
+ int m_interfaceNumber;
+ void setInterfaceNumber(int interfaceNumber);
+ };
+
+ /**
+ * \brief Class representing a configuration of a Device
+ *
+ * The Configuration class represents a single configuration
+ * of a device attached to a Universal Serial Bus.
+ *
+ * \author Brad Hards
+ */
+ class Configuration : public std::list<Interface *> {
+ /**
+ * Busses is a friend because it fills in the descriptor type
+ * information on initialisation and rescan.
+ */
+ friend class Busses;
+ public:
+ Configuration() {};
+
+ /**
+ * \brief Configuration descriptor information output
+ *
+ * This method dumps out the various characteristics
+ * of the configuration to standard output.
+ *
+ * It is mostly useful for debugging.
+ */
+ void dumpDescriptor(void);
+
+ /**
+ * \brief Number of Interfaces that this device has
+ *
+ * This is a simple accessor method that specifies the number
+ * Interfaces that this device configuration has.
+ */
+ u_int8_t numInterfaces(void);
+
+ /**
+ * \brief First Interface for the Configuration
+ *
+ * This method returns a pointer to the first Interface
+ * for the Configuration.
+ *
+ * See nextInterface() for an example of how it might be
+ * used.
+ *
+ * \see nextInterface(), lastInterface(), numInterfaces()
+ */
+ Interface *firstInterface(void);
+
+ /**
+ * \brief Next Interface for the Configuration
+ *
+ * This method returns a pointer to the next Interface
+ * for the Configuration.
+ *
+ * If you want to iterate through each Interface on
+ * a device, you can use something like the following:
+ * \code
+ * USB::Configuration *this_Configuration;
+ * this_Configuration = device->firstConfiguration();
+ * for (i=0; i < device->numConfigurations(); i++) {
+ * this_Interface = this_Configuration->firstInterface();
+ * for (j=0; j < this_Configuration->numInterfaces(); j++) {
+ * // do something with this_Interface
+ * this_Interface = this_Configuration->nextInterface();
+ * }
+ * this_Configuration->nextConfiguration();
+ * }
+ * \endcode
+ *
+ * \see firstInterface(), lastInterface(), numInterfaces()
+ */
+ Interface *nextInterface(void);
+
+ /**
+ * \brief Last Interface for the Configuration
+ *
+ * This method returns a pointer to the last Interface
+ * for the Configuration.
+ *
+ * \see firstInterface(), nextInterface(), numInterfaces()
+ */
+ Interface *lastInterface(void);
+
+ private:
+ std::list<Interface *>::const_iterator iter;
+
+ void setDescriptor(struct usb_config_descriptor);
+ /* we don't use a normal usb_config_descriptor */
+ /* because that would bring in the interface list */
+ u_int8_t m_Length;
+ u_int8_t m_DescriptorType;
+ u_int16_t m_TotalLength;
+ u_int8_t m_NumInterfaces;
+ u_int8_t m_ConfigurationValue;
+ u_int8_t m_Configuration;
+ u_int8_t m_Attributes;
+ u_int8_t m_MaxPower;
+ };
+
+ /**
+ * \brief Class representing a Device on the Bus
+ *
+ * The Device class represents a single device
+ * attached to a Universal Serial Bus.
+ *
+ * \author Brad Hards
+ */
+ class Device : public std::list<Configuration *> {
+ /**
+ * Busses is a friend because it fills in the descriptor type
+ * information on initialisation and rescan.
+ */
+ friend class Busses;
+ /**
+ * Interface is a friend because it needs the handle() function to
+ * perform claim(), release().
+ */
+ friend class Interface;
+ /**
+ * Endpoint is a friend because it needs the handle() function to
+ * perform reads, writes, and other transactions.
+ */
+ friend class Endpoint;
+
+ public:
+ Device() {};
+ ~Device();
+
+ /**
+ * \brief OS representation of filename for this device
+ *
+ * libusb++ provides a uniform way of accessing USB
+ * devices irrespective of the underlying Operation System
+ * representation. If you want to map the libusb++ representation
+ * to the Operating System representation, you can do this
+ * with filename().
+ *
+ * On Linux, the filename is usually something like 002, which
+ * represents the second device (usually the first real device,
+ * after the root hub pseudo-device) on the bus.
+ *
+ * \see Bus::directoryName()
+ */
+ std::string fileName(void);
+
+ /**
+ * \brief The vendor ID number, as provided by the device.
+ *
+ * This method returns a number containing the vendor
+ * (manufacturer) identification number. These are allocated
+ * by the USB Implementers Forum, and you can construct a
+ * lookup based on the number to get the manufacturer's name,
+ * even if the device does not contain a vendor string.
+ *
+ * \see Vendor()
+ */
+ u_int16_t idVendor(void);
+
+ /**
+ * \brief The product ID number, as provided by the device.
+ *
+ * This method returns a number containing the product
+ * identification number. These are allocated
+ * by the manufacturer, and should be different on each device.
+ *
+ * \see Product()
+ */
+ u_int16_t idProduct(void);
+
+ /**
+ * \brief The product's revision ID, as provided by the device.
+ *
+ * This method returns a number containing the product's revision.
+ * This revision level is nominally binary coded decimal, but
+ * hexadecimal revision levels are not uncommon. The binary coded
+ * decimal version nominally has a major version in the high byte,
+ * and a minor version in the low byte.
+ */
+ u_int16_t idRevision(void);
+
+ /**
+ * \brief The device's USB class, as provided by the device.
+ *
+ * This method returns a number containing the device's class.
+ * These are defined by the USB Implementer's Forum.
+ *
+ * A code of Zero is special (and common) - it means that the
+ * class is found in the Interface descriptor, rather than in the
+ * Device descriptor.
+ *
+ * A code of 0xFF is also special (and far too common) - it means
+ * that the manufacturer didn't conform to one of the defined
+ * class specifications, and chose to implement a vendor specified
+ * protocol.
+ *
+ */
+ u_int8_t devClass(void);
+
+ /**
+ * \brief The device's USB subclass, as provided by the device.
+ *
+ * This method returns a number containing the device's subclass.
+ * These subclasses are defined by the USB Implementer's Forum,
+ * and only have meaning in the context of a specified class.
+ */
+ u_int8_t devSubClass(void);
+
+ /**
+ * \brief The device's USB protocol, as provided by the device.
+ *
+ * This method returns a number containing the device's protocol.
+ * These protocols are defined by the USB Implementer's Forum, and
+ * only have meaning in the context of a specified class and
+ * subclass.
+ */
+ u_int8_t devProtocol(void);
+
+
+ /**
+ * \brief The vendor name string, as provided by the device.
+ *
+ * This method returns a string containing the name of the
+ * device's vendor (manufacturer), as encoded into the device.
+ *
+ * Note that not all devices contain a vendor name, and also
+ * that under some operating systems you may not be able to
+ * read the vendor name without elevated privledges (typically
+ * root privledges).
+ *
+ * \see idVendor()
+ **/
+ std::string Vendor(void);
+
+ /**
+ * \brief The product name string, as provided by the device.
+ *
+ * This method returns a string containing the name of the
+ * device's product name, as encoded into the device.
+ *
+ * Note that not all devices contain a product name, and also
+ * that under some operating systems you may not be able to
+ * read the vendor name without elevated privledges (typically
+ * root privledges).
+ *
+ * \see idProduct()
+ **/
+ std::string Product(void);
+
+ /**
+ * \brief The serial number string, as provided by the device.
+ *
+ * This method returns a string containing a serial number for
+ * the device, as encoded into the device.
+ *
+ * Note that few devices contain a serial number string, and also
+ * that under some operating systems you may not be able to
+ * read the serial number without elevated privledges (typically
+ * root privledges). The USB specification requires that serial
+ * numbers are unique if they are provided, but adherence to this
+ * requirement by manufacturers is not universal.
+ **/
+ std::string SerialNumber(void);
+
+ /**
+ * \brief Number of Configurations that this device has
+ *
+ * This is a simple accessor method that specifies the number
+ * configurations that this device has.
+ */
+ u_int8_t numConfigurations(void);
+
+ /**
+ * \brief fetch an arbitrary string from the device
+ *
+ * \param string the string from the device. You can typically
+ * pass in an empty string for this.
+ * \param index the index of the string required
+ * \param lang the language ID to use. Defaults to using the
+ * first language ID.
+ *
+ * \return length of string, or 0 on error.
+ */
+ int string(std::string &buf, int index, u_int16_t lang=0);
+
+ /**
+ * \brief First Configuration for the Device
+ *
+ * This method returns a pointer to the first Configuration
+ * for the Device.
+ *
+ * See nextConfiguration() for an example of how it might be
+ * used.
+ */
+ Configuration *firstConfiguration(void);
+
+ /**
+ * \brief Next Configuration for the Device
+ *
+ * This method returns a pointer to the next Configuration
+ * for the Device.
+ *
+ * If you want to iterate through each Configuration on
+ * a device, you can use something like the following:
+ * \code
+ * USB::Configuration *this_Configuration;
+ * this_Configuration = device->firstConfiguration();
+ * for (i=0; i < device->numConfigurations(); i++) {
+ * // do something with this_Configuration
+ * this_Configuration->nextConfiguration();
+ * }
+ * \endcode
+ */
+ Configuration *nextConfiguration(void);
+
+ /**
+ * \brief Last Configuration for the Device
+ *
+ * This method returns a pointer to the last Configuration
+ * for the Device.
+ *
+ */
+ Configuration *lastConfiguration(void);
+
+ /**
+ * \brief USB control transfer
+ *
+ * This method performs a standard control transfer to the default
+ * endpoint. See the USB specification for more details on this.
+ *
+ * \param requestType corresponds to the bmRequestType field
+ * in the transfer
+ * \param request corresponds to the bRequest field in the
+ * transfer
+ * \param value corresponds to the wValue field in the transfer
+ * \param index corresponds to the wIndex field in the transfer
+ * \param length corresponds to the wLength field in the transfer
+ * \param payload corresponds to the data phase of a control
+ * transfer
+ * \param timeout is the timeout period for the control transfer,
+ * in milliseconds
+ *
+ * \return number of bytes sent or received, or a negative number
+ * in case of error.
+ */
+ int controlTransfer(u_int8_t requestType, u_int8_t request,
+ u_int16_t value, u_int16_t index, u_int16_t length,
+ unsigned char *payload,
+ int timeout = 100);
+
+#ifdef USE_UNTESTED_LIBUSBPP_METHODS
+ /**
+ * \brief USB device reset
+ *
+ * This method performs a device reset - see USB Specification
+ * 9.1 for how this changes the device state to the Default state.
+ *
+ * \return 0 on success, or a negative number in case of error.
+ */
+ int reset(void);
+
+ /**
+ * \brief Set device configuration
+ *
+ * This method sets the device to a particular Configuration.
+ *
+ * \param configurationNumber the configuration that the device
+ * should be changed to.
+ *
+ * \return 0 on success, or a negative number in case of error.
+ */
+ int setConfiguration(int configurationNumber);
+#endif /* USE_UNTESTED_LIBUSBPP_METHODS */
+
+ private:
+ std::list<Configuration *>::const_iterator iter;
+
+ struct usb_dev_handle *handle();
+ void setFileName(std::string);
+ void setDescriptor(struct usb_device_descriptor);
+ void setVendor(std::string);
+ void setProduct(std::string);
+ void setSerialNumber(std::string);
+ void setDevHandle(struct usb_dev_handle *);
+ std::string m_fileName;
+ std::string m_Vendor;
+ std::string m_Product;
+ std::string m_SerialNumber;
+ struct usb_device *m_dev;
+ struct usb_dev_handle *m_handle;
+ struct usb_device_descriptor m_descriptor;
+ };
+
+ /**
+ * \brief Class representing a single bus on the machine
+ *
+ * This class is essentially a list of Device class instances
+ */
+ class Bus : public std::list<Device *> {
+ /**
+ * Busses is a friend because it fills in the directory name
+ * information on initialisation and rescan.
+ */
+ friend class Busses;
+ public:
+ Bus() {};
+ /**
+ * \brief OS representation of directory name for this Bus
+ *
+ * libusb++ provides a uniform way of accessing USB
+ * busses irrespective of the underlying Operation System
+ * representation. If you want to map the libusb++ representation
+ * to the Operating System representation, you can do this
+ * with directory name().
+ *
+ * On Linux, the directoryname is usually something like 003, which
+ * represents the third bus on the host.
+ *
+ * \see Directory::filename()
+ */
+ std::string directoryName(void);
+ private:
+ std::list<Device *>::const_iterator iter;
+
+ void setDirectoryName(std::string);
+ std::string m_directoryName;
+ };
+
+ /**
+ * \brief A vendor/product ID pair
+ *
+ * DeviceID provides a list of (vendor, product) identification
+ * pairs. It is intended for use in a list of device numbers to
+ * search for, but there is no reason why it couldn't be used for a
+ * general purpose (vendor,product) tuple if you had some reason for
+ * this.
+ *
+ * The description for Busses::match() provides an example of how
+ * this class might be used.
+ *
+ * \see DeviceIDList, Busses::match()
+ */
+ class DeviceID {
+ public:
+ DeviceID() {};
+ /**
+ * \brief Standard constructor
+ *
+ * This constructor takes (vendor, product) tuple, which are
+ * stored away.
+ *
+ * \param vendor the 16 bit vendor number for the device
+ * \param product the 16 bit product number for the device
+ */
+ DeviceID(u_int16_t vendor, u_int16_t product);
+
+ /**
+ * \brief vendor number for the device
+ *
+ * This method returns the 16 bit vendor number.
+ */
+ u_int16_t vendor(void);
+
+ /**
+ * \brief product number for the device
+ *
+ * This method returns the 16 bit product number.
+ */
+ u_int16_t product(void);
+
+ private:
+ u_int16_t m_vendor;
+ u_int16_t m_product;
+ };
+
+ /**
+ * \brief A list of vendor/product pairs
+ *
+ * DeviceIDList provides a list of DeviceID classes, which is
+ * essentially a list of (vendor, product) identification pairs.
+ *
+ * \see DeviceID
+ */
+ typedef std::list<DeviceID> DeviceIDList;
+
+ /**
+ * \brief Class representing all the busses on the machine
+ *
+ * This class is essentially a list of Bus class instances
+ */
+ class Busses : public std::list<Bus *> {
+ public:
+ Busses();
+
+ /**
+ * \brief Update method
+ *
+ * This method can be called to rescan the various devices
+ * attached to the various busses. You should use it to
+ * update if things change. Unfortunately there is no
+ * way to automatically detect this change in a portable way,
+ * so worst case is that you need to call this using some
+ * kind of timer in the background.
+ */
+ void rescan(void);
+
+ /**
+ * \brief find all devices with matching device class designator
+ *
+ * This method searches every device on every bus, and returns a
+ * list of pointers to the devices that have a matching device
+ * class code
+ */
+ std::list<Device *> match(u_int8_t Class);
+
+ /**
+ * \brief find all devices with matching device IDs
+ *
+ * This method searches every device on every bus, and returns a
+ * list of pointers to the devices that have a matching device
+ * ID. That is, if the (vendor, product) tuple of a device matches
+ * one of the tuples on the list, then the device will be added to
+ * the list of matches.
+ *
+ * An example of usage is shown below:
+ * \code
+ * USB::Busses buslist;
+ * USB::Device *device;
+ * std::list<USB::Device> miceFound;
+ * USB::DeviceIDList mouseList;
+ *
+ * mouseList.append(USB::DeviceID(VENDOR_LOGITECH, 0xC00E)); // Wheel Mouse Optical
+ * mouseList.append(USB::DeviceID(VENDOR_LOGITECH, 0xC012)); // MouseMan Dual Optical
+ * mouseList.append(USB::DeviceID(VENDOR_LOGITECH, 0xC506)); // MX700 Optical Mouse
+ *
+ * miceFound = buslist.match(mouseList);
+ *
+ * for ( device = miceFound.first(); device; device = miceFound.next() ) {
+ * // do something with each mouse that matched
+ * }
+ * FIXME: This is incorrect now
+ * \endcode
+ */
+ std::list<Device *> match(DeviceIDList);
+
+ private:
+ std::list<Bus *>::const_iterator iter;
+ };
+
+ class Error {
+ public:
+ private:
+ };
+
+}
+#endif /* __USBPP_HEADER__ */
+