From 4ef235035010b0195be908800bf41f899297e885 Mon Sep 17 00:00:00 2001
From: joerg_wunsch <joerg_wunsch@81a1dc3b-b13d-400b-aceb-764788c761c2>
Date: Wed, 17 Aug 2011 15:24:09 +0000
Subject: [PATCH] Submitted by Grygoriy Fuchedzhy: bug #31779: Add support for
 addressing usbtinyisp with -P option * usbtiny.c (usbtiny_open): Add logic to
 distinguish multiple USBtinyISP programmers by their bus:device tuple. *
 doc/avrdude.texi: Document the new functionality. * avrdude.1: (Ditto.)

git-svn-id: svn://svn.savannah.nongnu.org/avrdude/trunk/avrdude@974 81a1dc3b-b13d-400b-aceb-764788c761c2
---
 ChangeLog        |  9 +++++++++
 avrdude.1        | 10 ++++++++--
 doc/avrdude.texi | 30 ++++++++++++++++++++++++++----
 usbtiny.c        | 31 ++++++++++++++++++++++++++++++-
 4 files changed, 73 insertions(+), 7 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index ec3084f9..20c9de82 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,12 @@
+2011-08-17  Joerg Wunsch <j.gnu@uriah.heep.sax.de>
+
+	Submitted by Grygoriy Fuchedzhy:
+	bug #31779: Add support for addressing usbtinyisp with -P option
+	* usbtiny.c (usbtiny_open): Add logic to distinguish multiple USBtinyISP
+	programmers by their bus:device tuple.
+	* doc/avrdude.texi: Document the new functionality.
+	* avrdude.1: (Ditto.)
+
 2011-08-16  Joerg Wunsch <j.gnu@uriah.heep.sax.de>
 
 	Submitted by Timon Van Overveldt:
diff --git a/avrdude.1 b/avrdude.1
index 3da8b556..c168819b 100644
--- a/avrdude.1
+++ b/avrdude.1
@@ -1,6 +1,6 @@
 .\"
 .\" avrdude - A Downloader/Uploader for AVR device programmers
-.\" Copyright (C) 2001, 2002, 2003, 2005 - 2010  Joerg Wunsch
+.\" Copyright (C) 2001, 2002, 2003, 2005 - 2011  Joerg Wunsch
 .\"
 .\" This program is free software; you can redistribute it and/or modify
 .\" it under the terms of the GNU General Public License as published by
@@ -19,7 +19,7 @@
 .\"
 .\" $Id$
 .\"
-.Dd DATE January 14, 2010
+.Dd DATE August 17, 2011
 .Os
 .Dt AVRDUDE 1
 .Sh NAME
@@ -511,6 +511,12 @@ be specified as
 Libusb support is required on Unix but not on Windows. For more
 information about AVR-Doper see http://www.obdev.at/avrusb/avrdoper.html.
 .Pp
+For the USBtinyISP, which is a simplicistic device not implementing
+serial numbers, multiple devices can be distinguished by their
+location in the USB hierarchy.  See the the respective
+.Em Troubleshooting
+entry in the detailed documentation for examples.
+.Pp
 For programmers that attach to a serial port using some kind of
 higher level protocol (as opposed to bit-bang style programmers),
 .Ar port
diff --git a/doc/avrdude.texi b/doc/avrdude.texi
index 7b8ec831..b18d8378 100644
--- a/doc/avrdude.texi
+++ b/doc/avrdude.texi
@@ -30,7 +30,7 @@ For avrdude version @value{VERSION}, @value{UPDATED}.
 
 Copyright @copyright{} 2003, 2005 Brian Dean
 
-Copyright @copyright{} 2006 - 2010 J@"org Wunsch
+Copyright @copyright{} 2006 - 2011 J@"org Wunsch
 
 Permission is granted to make and distribute verbatim copies of
 this manual provided the copyright notice and this permission notice
@@ -707,6 +707,11 @@ be specified as @var{avrdoper}. Libusb support is required on Unix
 but not on Windows. For more information about AVR-Doper see
 @url{http://www.obdev.at/avrusb/avrdoper.html}.
 
+For the USBtinyISP, which is a simplicistic device not implementing
+serial numbers, multiple devices can be distinguished by their
+location in the USB hierarchy.
+@xref{Troubleshooting} for examples.
+
 For programmers that attach to a serial port using some kind of
 higher level protocol (as opposed to bit-bang style programmers),
 @var{port} can be specified as @code{net}:@var{host}:@var{port}.
@@ -2324,9 +2329,26 @@ The pin mapping for the JTAG-to-ISP adapter is:
 Problem: Multiple USBasp or USBtinyISP programmers connected simultaneously are not
 found.
 
-Solution: none at this time.  The simplicity of these programmers
-doesn't offer a method to distinguish multiple programmers that are
-connected simultaneously, so effectively only one of them is supported.
+Solution: The USBtinyISP code supports distinguishing multiple
+programmers based on their bus:device connection tuple that describes
+their place in the USB hierarchy on a specific host.  This tuple can
+be added to the @var{-P usb} option, similar to adding a serial number
+on other USB-based programmers.
+
+The actual naming convention for the bus and device names is
+operating-system dependant; AVRDUDE will print out what it found
+on the bus when running it with (at least) one @var{-v} option.
+By specifying a string that cannot match any existing device
+(for example, @var{-P usb:xxx}), the scan will list all possible
+candidate devices found on the bus.
+
+Examples:
+@example
+avrdude -c usbtiny -p atmega8 -P usb:003:025 (Linux)
+avrdude -c usbtiny -p atmega8 -P usb:/dev/usb:/dev/ugen1.3 (FreeBSD 8+)
+avrdude -c usbtiny -p atmega8 \
+  -P usb:bus-0/\\.\libusb0-0001--0x1781-0x0c9f (Windows)
+@end example
 
 @item
 Problem: I cannot do @dots{} when the target is in debugWire mode.
diff --git a/usbtiny.c b/usbtiny.c
index 9bc821d4..638e2a13 100644
--- a/usbtiny.c
+++ b/usbtiny.c
@@ -36,6 +36,7 @@
 #include "avrdude.h"
 #include "avr.h"
 #include "pgm.h"
+#include "config.h"
 #include "usbtiny.h"
 
 #if defined(HAVE_LIBUSB)      // we use LIBUSB to talk to the board
@@ -196,6 +197,22 @@ static	int	usbtiny_open(PROGRAMMER* pgm, char* name)
 {
   struct usb_bus      *bus;
   struct usb_device   *dev = 0;
+  char *bus_name;
+  char *dev_name = NULL;
+
+  // if no -P was given or '-P usb' was given
+  if(name == default_parallel || strcmp(name, "usb") == 0)
+    name = NULL;
+  else {
+    // calculate bus and device names from -P option
+    const size_t usb_len = strlen("usb");
+    if(strncmp(name, "usb", usb_len) == 0 && ':' == name[usb_len]) {
+        bus_name = name + usb_len + 1;
+        dev_name = strchr(bus_name, ':');
+        if(NULL != dev_name)
+          *dev_name++ = '\0';
+    }
+  }
 
   usb_init();                    // initialize the libusb system
   usb_find_busses();             // have libusb scan all the usb busses available
@@ -208,7 +225,14 @@ static	int	usbtiny_open(PROGRAMMER* pgm, char* name)
     for	( dev = bus->devices; dev; dev = dev->next ) {
       if (dev->descriptor.idVendor == USBTINY_VENDOR
 	  && dev->descriptor.idProduct == USBTINY_PRODUCT ) {   // found match?
-
+    if(verbose)
+      printf("avrdude: usbdev_open(): Found USBtinyISP, bus:device: %s:%s\n", bus->dirname, dev->filename);
+    // if -P was given, match device by device name and bus name
+    if(name != NULL &&
+      (NULL == dev_name ||
+       strcmp(bus->dirname, bus_name) ||
+       strcmp(dev->filename, dev_name)))
+      continue;
 	PDATA(pgm)->usb_handle = usb_open(dev);           // attempt to connect to device
 
 	// wrong permissions or something?
@@ -221,6 +245,11 @@ static	int	usbtiny_open(PROGRAMMER* pgm, char* name)
     }
   }
 
+  if(NULL != name && NULL == dev_name) {
+    fprintf(stderr, "%s: Error: Invalid -P value: '%s'\n", progname, name);
+    fprintf(stderr, "%sUse -P usb:bus:device\n", progbuf);
+    return -1;
+  }
   if (!PDATA(pgm)->usb_handle) {
     fprintf( stderr, "%s: Error: Could not find USBtiny device (0x%x/0x%x)\n",
 	     progname, USBTINY_VENDOR, USBTINY_PRODUCT );