File usbutils.libusb0-1.patch of Package usbutils

---
 Makefile.am   |    5 
 configure.in  |    2 
 descriptors.c |  520 +++++++++++++++++++++++++++++++++++++++++
 error.c       |   36 ++
 error.h       |   31 ++
 linux.c       |  733 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 linux.h       |  119 +++++++++
 usb.c         |  307 ++++++++++++++++++++++++
 usb.h         |  338 ++++++++++++++++++++++++++
 usbi.h        |   74 +++++
 10 files changed, 2163 insertions(+), 2 deletions(-)

--- a/Makefile.am
+++ b/Makefile.am
@@ -7,6 +7,11 @@ AM_CFLAGS = -Wall -W -Wunused
 sbin_PROGRAMS = lsusb
 
 lsusb_SOURCES = lsusb.c \
+	usbi.h \
+	usb.c usb.h \
+	error.c error.h \
+	linux.c linux.h \
+	descriptors.c \
 	lsusb-t.c \
 	names.c names.h \
 	devtree.c devtree.h list.h \
--- a/configure.in
+++ b/configure.in
@@ -31,8 +31,6 @@ AC_TYPE_SIZE_T
 AC_FUNC_MALLOC
 AC_FUNC_VPRINTF
 AC_CHECK_FUNCS([getcwd memset getopt_long strchr strerror strstr strtoul uname])
-AC_CHECK_LIB(usb, usb_get_string_simple, ,
-	[AC_MSG_ERROR(get libusb 0.1.8 or newer)])
 
 
 dnl zlib on enabled by default (if found)
--- /dev/null
+++ b/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;
+}
+
--- /dev/null
+++ b/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";
+}
+
--- /dev/null
+++ b/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_ */
+
--- /dev/null
+++ b/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;
+}
+
--- /dev/null
+++ b/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
+
--- /dev/null
+++ b/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);
+}
+
--- /dev/null
+++ b/usb.h
@@ -0,0 +1,338 @@
+/*
+ * 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.
+ */
+#include <endian.h>
+#if __BYTE_ORDER == __BIG_ENDIAN
+#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 /* LINUX_API */
+#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__ */
+
--- /dev/null
+++ b/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_ */
+
openSUSE Build Service is sponsored by