From 6faf7bad31ca5a2880f4eeeb84784c66a1bdd465 Mon Sep 17 00:00:00 2001
From: springob <springob@81a1dc3b-b13d-400b-aceb-764788c761c2>
Date: Fri, 12 Mar 2010 18:27:56 +0000
Subject: [PATCH] * autodetection of libusb-1.0 added (for 64 bit windows 7
 support) * libusb-1.0 is used directly instead of libusb v0.1 when detected *
 nibobee vid/pid added to usbasp programmer

git-svn-id: svn://svn.savannah.nongnu.org/avrdude/trunk/avrdude@941 81a1dc3b-b13d-400b-aceb-764788c761c2
---
 configure.ac |  19 ++++++
 usbasp.c     | 190 ++++++++++++++++++++++++++++++++++++++++++++++++---
 usbasp.h     |   3 +
 3 files changed, 201 insertions(+), 11 deletions(-)

diff --git a/configure.ac b/configure.ac
index 595e6fa1..895cca7c 100644
--- a/configure.ac
+++ b/configure.ac
@@ -66,12 +66,31 @@ if test x$have_libusb = xyes; then
 fi
 AC_SUBST(LIBUSB, $LIBUSB)
 
+AH_TEMPLATE([HAVE_LIBUSB_1_0],
+            [Define if USB support is enabled via libusb 1.0])
+AC_CHECK_LIB([usb-1.0], [libusb_init], [have_libusb_1_0=yes])
+if test x$have_libusb_1_0 = xyes; then
+   case $target in
+       *-*-darwin*)
+               LIBUSB_1_0="-lusb-1.0 -framework CoreFoundation -framework IOKit"
+               ;;
+       *)
+               LIBUSB_1_0="-lusb-1.0"
+               ;;
+   esac
+   AC_DEFINE([HAVE_LIBUSB_1_0])
+   AC_CHECK_HEADERS([libusb-1.0/libusb.h])
+   AC_CHECK_HEADERS([libusb.h])
+fi
+AC_SUBST(LIBUSB_1_0, $LIBUSB_1_0)
+
 # Checks for header files.
 AC_CHECK_HEADERS([limits.h stdlib.h string.h])
 AC_CHECK_HEADERS([fcntl.h sys/ioctl.h sys/time.h termios.h unistd.h])
 AC_CHECK_HEADERS([ddk/hidsdi.h],,,[#include <windows.h>
 #include <setupapi.h>])
 
+
 # Checks for typedefs, structures, and compiler characteristics.
 AC_C_CONST
 AC_HEADER_TIME
diff --git a/usbasp.c b/usbasp.c
index ff7d71e2..b14cfbef 100644
--- a/usbasp.c
+++ b/usbasp.c
@@ -39,15 +39,73 @@
 #include "pgm.h"
 #include "usbasp.h"
 
-#ifdef HAVE_LIBUSB
-#include <usb.h>
+#if defined(HAVE_LIBUSB) || defined(HAVE_LIBUSB_1_0)
+
+#ifdef HAVE_LIBUSB_1_0
+# define USE_LIBUSB_1_0
+#endif
+
+#if defined(USE_LIBUSB_1_0)
+# if defined(HAVE_LIBUSB_1_0_LIBUSB_H)
+#  include <libusb-1.0/libusb.h>
+# else
+#  include <libusb.h>
+# endif
+#else
+# include <usb.h>
+#endif
+
+#ifdef USE_LIBUSB_1_0
+
+static libusb_context *ctx = NULL;
+
+static int libusb_to_errno(int result)
+{
+	switch (result) {
+	case LIBUSB_SUCCESS:
+		return 0;
+	case LIBUSB_ERROR_IO:
+		return EIO;
+	case LIBUSB_ERROR_INVALID_PARAM:
+		return EINVAL;
+	case LIBUSB_ERROR_ACCESS:
+		return EACCES;
+	case LIBUSB_ERROR_NO_DEVICE:
+		return ENXIO;
+	case LIBUSB_ERROR_NOT_FOUND:
+		return ENOENT;
+	case LIBUSB_ERROR_BUSY:
+		return EBUSY;
+	case LIBUSB_ERROR_TIMEOUT:
+		return ETIMEDOUT;
+	case LIBUSB_ERROR_OVERFLOW:
+		return EOVERFLOW;
+	case LIBUSB_ERROR_PIPE:
+		return EPIPE;
+	case LIBUSB_ERROR_INTERRUPTED:
+		return EINTR;
+	case LIBUSB_ERROR_NO_MEM:
+		return ENOMEM;
+	case LIBUSB_ERROR_NOT_SUPPORTED:
+		return ENOSYS;
+	default:
+		return ERANGE;
+	}
+}
+
+#endif
+
 
 /*
  * Private data for this programmer.
  */
 struct pdata
 {
+#ifdef USE_LIBUSB_1_0
+  libusb_device_handle *usbhandle;
+#else
   usb_dev_handle *usbhandle;
+#endif
   int sckfreq_hz; 
 };
 
@@ -78,6 +136,20 @@ static int usbasp_transmit(PROGRAMMER * pgm,
 			   unsigned char send[4], unsigned char * buffer, int buffersize)
 {
   int nbytes;
+#ifdef USE_LIBUSB_1_0
+  nbytes = libusb_control_transfer(PDATA(pgm)->usbhandle,
+				   (LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE | (receive << 7)) & 0xff,
+				   functionid & 0xff, 
+				   ((send[1] << 8) | send[0]) &  0xffff, 
+				   ((send[3] << 8) | send[2]) & 0xffff, 
+				   (char *)buffer, 
+				   buffersize & 0xffff,
+				   5000);
+  if(nbytes < 0){
+    fprintf(stderr, "%s: error: usbasp_transmit: %s\n", progname, strerror(libusb_to_errno(nbytes)));
+    exit(1);
+  }
+#else
   nbytes = usb_control_msg(PDATA(pgm)->usbhandle,
 			   USB_TYPE_VENDOR | USB_RECIP_DEVICE | (receive << 7),
 			   functionid,
@@ -89,7 +161,7 @@ static int usbasp_transmit(PROGRAMMER * pgm,
     fprintf(stderr, "%s: error: usbasp_transmit: %s\n", progname, usb_strerror());
     exit(1);
   }
-
+#endif
   return nbytes;
 }
 
@@ -100,14 +172,93 @@ static int usbasp_transmit(PROGRAMMER * pgm,
  * DEVELOPMENT Software GmbH (www.obdev.at) to meet conditions for
  * shared VID/PID
  */
+#ifdef USE_LIBUSB_1_0
+static int usbOpenDevice(libusb_device_handle **device, int vendor,
+			 char *vendorName, int product, char *productName)
+{
+    libusb_device_handle *handle = NULL;
+    int                  errorCode = USB_ERROR_NOTFOUND;
+    static int           didUsbInit = 0;
+    int j;
+    int r;
+
+    if(!didUsbInit){
+        didUsbInit = 1;
+        libusb_init(&ctx);
+    }
+    
+    libusb_device **dev_list;
+    int dev_list_len = libusb_get_device_list(ctx, &dev_list);
+
+    for (j=0; j<dev_list_len; ++j) {
+        libusb_device *dev = dev_list[j];
+        struct libusb_device_descriptor descriptor;
+	libusb_get_device_descriptor(dev, &descriptor);
+	if (descriptor.idVendor == vendor && descriptor.idProduct == product) {
+            char    string[256];
+	    /* we need to open the device in order to query strings */
+            r = libusb_open(dev, &handle);
+            if (!handle) {
+                 errorCode = USB_ERROR_ACCESS;
+                 fprintf(stderr,
+			    "%s: Warning: cannot open USB device: %s\n",
+			    progname, strerror(libusb_to_errno(r)));
+                    continue;
+                }
+                if (vendorName == NULL && productName == NULL) {
+		    /* name does not matter */
+                    break;
+                }
+                /* now check whether the names match: */
+		r = libusb_get_string_descriptor_ascii(handle, descriptor.iManufacturer & 0xff, string, sizeof(string));
+                if (r < 0) {
+                    errorCode = USB_ERROR_IO;
+                    fprintf(stderr,
+			    "%s: Warning: cannot query manufacturer for device: %s\n",
+			    progname, strerror(libusb_to_errno(r)));
+                } else {
+                    errorCode = USB_ERROR_NOTFOUND;
+		    if (verbose > 1)
+		        fprintf(stderr,
+				"%s: seen device from vendor ->%s<-\n",
+				progname, string);
+                    if (strcmp(string, vendorName) == 0){
+			r = libusb_get_string_descriptor_ascii(handle, descriptor.iProduct & 0xff, string, sizeof(string));
+                        if (r < 0) {
+                            errorCode = USB_ERROR_IO;
+                            fprintf(stderr,
+				    "%s: Warning: cannot query product for device: %s\n",
+				    progname, strerror(libusb_to_errno(r)));
+                        } else {
+                            errorCode = USB_ERROR_NOTFOUND;
+			    if (verbose > 1)
+			        fprintf(stderr,
+					"%s: seen product ->%s<-\n",
+					progname, string);
+                            if(strcmp(string, productName) == 0)
+                                break;
+                        }
+                    }
+                }
+                libusb_close(handle);
+                handle = NULL;
+            }
+    }
+    if (handle != NULL){
+        errorCode = 0;
+        *device = handle;
+    }
+    return errorCode;
+}
+#else
 static int usbOpenDevice(usb_dev_handle **device, int vendor,
 			 char *vendorName, int product, char *productName)
 {
-struct usb_bus      *bus;
-struct usb_device   *dev;
-usb_dev_handle      *handle = NULL;
-int                 errorCode = USB_ERROR_NOTFOUND;
-static int          didUsbInit = 0;
+struct usb_bus       *bus;
+struct usb_device    *dev;
+usb_dev_handle       *handle = NULL;
+int                  errorCode = USB_ERROR_NOTFOUND;
+static int           didUsbInit = 0;
 
     if(!didUsbInit){
         didUsbInit = 1;
@@ -180,13 +331,26 @@ static int          didUsbInit = 0;
     }
     return errorCode;
 }
-
+#endif
 
 static int usbasp_open(PROGRAMMER * pgm, char * port)
 {
+#ifdef USE_LIBUSB_1_0
+  libusb_init(&ctx);
+#else
   usb_init();
-
-  if (usbOpenDevice(&PDATA(pgm)->usbhandle, USBASP_SHARED_VID, "www.fischl.de",
+#endif
+  if(strcasecmp(port, "nibobee") == 0) {
+    if (usbOpenDevice(&PDATA(pgm)->usbhandle, USBASP_NIBOBEE_VID, "www.nicai-systems.com",
+		    USBASP_NIBOBEE_PID, "NIBObee") != 0) {
+      fprintf(stderr,
+	      "%s: error: could not find USB device "
+	      "\"NIBObee\" with vid=0x%x pid=0x%x\n",
+  	      progname, USBASP_NIBOBEE_VID, USBASP_NIBOBEE_PID);
+      exit(1);
+      
+    }
+  } else if (usbOpenDevice(&PDATA(pgm)->usbhandle, USBASP_SHARED_VID, "www.fischl.de",
 		    USBASP_SHARED_PID, "USBasp") != 0) {
 
     /* check if device with old VID/PID is available */
@@ -220,7 +384,11 @@ static void usbasp_close(PROGRAMMER * pgm)
   memset(temp, 0, sizeof(temp));
   usbasp_transmit(pgm, 1, USBASP_FUNC_DISCONNECT, temp, temp, sizeof(temp));
 
+#ifdef USE_LIBUSB_1_0
+  libusb_close(PDATA(pgm)->usbhandle);
+#else
   usb_close(PDATA(pgm)->usbhandle);
+#endif
 }
 
 
diff --git a/usbasp.h b/usbasp.h
index c0d4468f..c9610acf 100644
--- a/usbasp.h
+++ b/usbasp.h
@@ -31,6 +31,9 @@
 #define	USBASP_OLD_VID      0x03EB  /* ATMEL */
 #define	USBASP_OLD_PID	    0xC7B4  /* (unoffical) USBasp */
 
+#define	USBASP_NIBOBEE_VID  0x16C0  /* VOTI */
+#define	USBASP_NIBOBEE_PID  0x092F  /* NIBObee PID */
+
 /* USB function call identifiers */
 #define USBASP_FUNC_CONNECT    1
 #define USBASP_FUNC_DISCONNECT 2