From 32c8b8a43039401904afaeb0e8bc284af33116f5 Mon Sep 17 00:00:00 2001
From: Joerg Wunsch <j@uriah.heep.sax.de>
Date: Sun, 17 Sep 2006 20:35:36 +0000
Subject: [PATCH] Submitted by Thomas Fischl: * usbasp.c: Check for USBasp with
 new as well as old VID/PID pair, warn the user about upgrading the firmware
 in case an old one has been found. * usbasp.h: Add new VID/PID.

git-svn-id: svn://svn.savannah.nongnu.org/avrdude/trunk/avrdude@661 81a1dc3b-b13d-400b-aceb-764788c761c2
---
 ChangeLog |   8 ++++
 usbasp.c  | 135 ++++++++++++++++++++++++++++++++++++++++++++----------
 usbasp.h  |  10 +++-
 3 files changed, 128 insertions(+), 25 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index e4e27ef5..16efc7bc 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,11 @@
+2006-09-17 Joerg Wunsch <j@uriah.heep.sax.de>
+
+	Submitted by Thomas Fischl:
+	* usbasp.c: Check for USBasp with new as well as old VID/PID
+	pair, warn the user about upgrading the firmware in case an
+	old one has been found.
+	* usbasp.h: Add new VID/PID.
+
 2006-09-15 Joerg Wunsch <j@uriah.heep.sax.de>
 
 	* avrdude.conf.in: Fix some mistakes for the ATtinyX61 family:
diff --git a/usbasp.c b/usbasp.c
index 013ff6b0..f931c1c2 100644
--- a/usbasp.c
+++ b/usbasp.c
@@ -40,6 +40,7 @@
 #ifdef HAVE_LIBUSB
 #include <usb.h>
 
+extern int    verbose;
 extern char * progname;
 extern int do_cycles;
 
@@ -67,33 +68,121 @@ static int usbasp_transmit(unsigned char receive, unsigned char functionid,
   return nbytes;
 }
 
+
+/*
+ * Try to open USB device with given VID, PID, vendor and product name
+ * Parts of this function were taken from an example code by OBJECTIVE
+ * DEVELOPMENT Software GmbH (www.obdev.at) to meet conditions for
+ * shared VID/PID
+ */
+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;
+
+    if(!didUsbInit){
+        didUsbInit = 1;
+        usb_init();
+    }
+    usb_find_busses();
+    usb_find_devices();
+    for(bus=usb_get_busses(); bus; bus=bus->next){
+        for(dev=bus->devices; dev; dev=dev->next){
+            if(dev->descriptor.idVendor == vendor &&
+	       dev->descriptor.idProduct == product){
+                char    string[256];
+                int     len;
+		/* we need to open the device in order to query strings */
+                handle = usb_open(dev);
+                if(!handle){
+                    errorCode = USB_ERROR_ACCESS;
+                    fprintf(stderr,
+			    "%s: Warning: cannot open USB device: %s\n",
+			    progname, usb_strerror());
+                    continue;
+                }
+                if(vendorName == NULL && productName == NULL){
+		    /* name does not matter */
+                    break;
+                }
+                /* now check whether the names match: */
+                len = usb_get_string_simple(handle, dev->descriptor.iManufacturer,
+					    string, sizeof(string));
+                if(len < 0){
+                    errorCode = USB_ERROR_IO;
+                    fprintf(stderr,
+			    "%s: Warning: cannot query manufacturer for device: %s\n",
+			    progname, usb_strerror());
+                }else{
+                    errorCode = USB_ERROR_NOTFOUND;
+		    if (verbose > 1)
+		        fprintf(stderr,
+				"%s: seen device from vendor ->%s<-\n",
+				progname, string);
+                    if(strcmp(string, vendorName) == 0){
+                        len = usb_get_string_simple(handle, dev->descriptor.iProduct,
+						    string, sizeof(string));
+                        if(len < 0){
+                            errorCode = USB_ERROR_IO;
+                            fprintf(stderr,
+				    "%s: Warning: cannot query product for device: %s\n",
+				    progname, usb_strerror());
+                        }else{
+                            errorCode = USB_ERROR_NOTFOUND;
+			    if (verbose > 1)
+			        fprintf(stderr,
+					"%s: seen product ->%s<-\n",
+					progname, string);
+                            if(strcmp(string, productName) == 0)
+                                break;
+                        }
+                    }
+                }
+                usb_close(handle);
+                handle = NULL;
+            }
+        }
+        if(handle)
+            break;
+    }
+    if(handle != NULL){
+        errorCode = 0;
+        *device = handle;
+    }
+    return errorCode;
+}
+
+
 static int usbasp_open(PROGRAMMER * pgm, char * port)
 {
-  struct usb_bus	*bus;
-  struct usb_device *dev = 0;
-
   usb_init();
-  usb_find_busses();
-  usb_find_devices();
-  for(bus=usb_busses; bus; bus=bus->next){
-    for(dev=bus->devices; dev; dev=dev->next){
-      if(dev->descriptor.idVendor == USBDEV_VENDOR && dev->descriptor.idProduct == USBDEV_PRODUCT)
-	break;
-    }
-    if(dev)
-      break;
-  }
-  if(!dev){
-    fprintf(stderr, "%s: error: could not find USB device vendor=0x%x product=0x%x\n",
-	    progname, USBDEV_VENDOR, USBDEV_PRODUCT);
-    exit(1);
-  }
 
-  usbhandle = usb_open(dev);
-  if(!usbhandle){
-    fprintf(stderr, "%s: error: opening usb device: %s\n",
-	    progname, usb_strerror());
-    exit(1);
+  if (usbOpenDevice(&usbhandle, USBASP_SHARED_VID, "www.fischl.de",
+		    USBASP_SHARED_PID, "USBasp") != 0) {
+
+    /* check if device with old VID/PID is available */
+    if (usbOpenDevice(&usbhandle, USBASP_OLD_VID, "www.fischl.de",
+		      USBASP_OLD_PID, "USBasp") != 0) {
+
+      /* no USBasp found */
+      fprintf(stderr,
+	      "%s: error: could not find USB device "
+	      "\"USBasp\" with vid=0x%x pid=0x%x\n",
+  	      progname, USBASP_SHARED_VID, USBASP_SHARED_PID);
+      exit(1);
+
+    } else {
+
+      /* found USBasp with old IDs */
+      fprintf(stderr,
+	      "%s: Warning: Found USB device \"USBasp\" with "
+	      "old VID/PID! Please update firmware of USBasp!\n",
+  	      progname);
+    }
   }
 
   return 0;
diff --git a/usbasp.h b/usbasp.h
index 9a2d37be..f2959628 100644
--- a/usbasp.h
+++ b/usbasp.h
@@ -25,8 +25,11 @@
 #include "avrpart.h"
 
 
-#define	USBDEV_VENDOR	0x03eb	/* ATMEL */
-#define	USBDEV_PRODUCT	0xc7B4 	/* USBasp */
+#define	USBASP_SHARED_VID   0x16C0  /* VOTI */
+#define	USBASP_SHARED_PID   0x05DC  /* Obdev's free shared PID */
+
+#define	USBASP_OLD_VID      0x03EB  /* ATMEL */
+#define	USBASP_OLD_PID	    0xC7B4  /* (unoffical) USBasp */
 
 #define USBASP_FUNC_CONNECT    1
 #define USBASP_FUNC_DISCONNECT 2
@@ -43,6 +46,9 @@
 #define USBASP_READBLOCKSIZE   200
 #define USBASP_WRITEBLOCKSIZE  200
 
+#define USB_ERROR_NOTFOUND  1
+#define USB_ERROR_ACCESS    2
+#define USB_ERROR_IO        3
 
 void usbasp_initpgm (PROGRAMMER * pgm);