From 7999eaa25a6b1a7bf917f260d18053e0b4db1a72 Mon Sep 17 00:00:00 2001
From: joerg_wunsch <joerg_wunsch@81a1dc3b-b13d-400b-aceb-764788c761c2>
Date: Thu, 27 Feb 2014 13:06:03 +0000
Subject: [PATCH] Turn the usbpid parameter of the programmer into a list of
 PIDs.  Make the JTAGICE3 programmer handle a list of PIDs, by trying each of
 them in sequence.  Use a single, central jtag3_open_common() function to
 handle the common code of all jtag3_open_* functions.  Centralize all USB
 VID/PID definitions in usbdevs.h.

git-svn-id: svn://svn.savannah.nongnu.org/avrdude/trunk/avrdude@1283 81a1dc3b-b13d-400b-aceb-764788c761c2
---
 ChangeLog       |  26 +++++++
 avrdude.conf.in |  44 ++----------
 avrftdi.c       |  16 +++--
 config_gram.y   |  30 ++++++--
 flip1.c         |  12 +++-
 flip2.c         |  11 ++-
 ft245r.c        |  16 ++++-
 jtag3.c         | 182 +++++++++++++++---------------------------------
 jtag3.h         |   1 +
 pgm.c           |   1 +
 pgm.h           |   3 +-
 serial.h        |   1 +
 stk500v2.c      |  38 ++--------
 usb_libusb.c    |   6 +-
 usbasp.c        |  18 ++++-
 usbasp.h        |  10 ---
 usbdevs.h       |  21 ++++++
 usbtiny.c       |  15 ++--
 usbtiny.h       |   5 --
 19 files changed, 223 insertions(+), 233 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index cbea0d2c..a56a3a3e 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,29 @@
+2014-02-27  Joerg Wunsch <j.gnu@uriah.heep.sax.de>
+
+	* config_gram.y: Turn the usbpid parameter of the programmer into
+	a list of PIDs.  Make the JTAGICE3 programmer handle a list of
+	PIDs, by trying each of them in sequence.  Use a single, central
+	jtag3_open_common() function to handle the common code of all
+	jtag3_open_* functions.  Centralize all USB VID/PID definitions in
+	usbdevs.h.
+	* flip1.c: (Dito.)
+	* ft245r.c: (Dito.)
+	* stk500v2.c: (Dito.)
+	* jtag3.c: (Dito.)
+	* jtag3.h: (Dito.)
+	* flip2.c: (Dito.)
+	* usbdevs.h: (Dito.)
+	* pgm.c: (Dito.)
+	* serial.h: (Dito.)
+	* pgm.h: (Dito.)
+	* usbtiny.c: (Dito.)
+	* usbasp.c: (Dito.)
+	* avrftdi.c: (Dito.)
+	* usbtiny.h: (Dito.)
+	* avrdude.conf.in: (Dito.)
+	* usbasp.h: (Dito.)
+	* usb_libusb.c: (Dito.)
+
 2014-02-27  Joerg Wunsch <j.gnu@uriah.heep.sax.de>
 
 	* usb_libusb.c (usbdev_open): Replace all calls to exit(1) by
diff --git a/avrdude.conf.in b/avrdude.conf.in
index e6a521bd..2fa90a7c 100644
--- a/avrdude.conf.in
+++ b/avrdude.conf.in
@@ -31,7 +31,7 @@
 #       pgmled   = <num> ;                          # pin number
 #       vfyled   = <num> ;                          # pin number
 #       usbvid   = <hexnum>;                        # USB VID (Vendor ID)
-#       usbpid   = <hexnum>;                        # USB PID (Product ID)
+#       usbpid   = <hexnum> [, <hexnum> ...]        # USB PID (Product ID) (1)
 #       usbdev   = <interface>;                     # USB interface or other device info 
 #       usbvendor = <vendorname>;                   # USB Vendor Name
 #       usbproduct = <productname>;                 # USB Product Name
@@ -41,6 +41,8 @@
 #        For a pin list all pins must be inverted.
 #        A single pin can be specified as usual = ~ <num>, for lists
 #        specify it as follows = ~ ( <num> [, <num2> ... ] ) .
+#
+#        (1) Not all programmer types can process a list of PIDs.
 #     ;
 #
 #   part
@@ -994,7 +996,7 @@ programmer
   desc  = "Atmel AVR JTAGICE3 in JTAG mode";
   type  = "jtagice3";
   connection_type = usb;
-  usbpid = 0x2110;
+  usbpid = 0x2110, 0x2140;
 ;
 
 programmer
@@ -1002,7 +1004,7 @@ programmer
   desc  = "Atmel AVR JTAGICE3 in PDI mode";
   type  = "jtagice3_pdi";
   connection_type = usb;
-  usbpid = 0x2110;
+  usbpid = 0x2110, 0x2140;
 ;
 
 programmer
@@ -1010,7 +1012,7 @@ programmer
   desc  = "Atmel AVR JTAGICE3 in debugWIRE mode";
   type  = "jtagice3_dw";
   connection_type = usb;
-  usbpid = 0x2110;
+  usbpid = 0x2110, 0x2140;
 ;
 
 programmer
@@ -1018,39 +1020,7 @@ programmer
   desc  = "Atmel AVR JTAGICE3 in ISP mode";
   type  = "jtagice3_isp";
   connection_type = usb;
-  usbpid = 0x2110;
-;
-
-programmer
-  id    = "jtag3edbg";
-  desc  = "Atmel AVR JTAGICE3 in JTAG mode, EDBG protocol";
-  type  = "jtagice3";
-  connection_type = usb;
-  usbpid = 0x2140;
-;
-
-programmer
-  id    = "jtag3pdi_edbg";
-  desc  = "Atmel AVR JTAGICE3 in PDI mode, EDBG protocol";
-  type  = "jtagice3_pdi";
-  connection_type = usb;
-  usbpid = 0x2140;
-;
-
-programmer
-  id    = "jtag3dw_edbg";
-  desc  = "Atmel AVR JTAGICE3 in debugWIRE mode, EDBG protocol";
-  type  = "jtagice3_dw";
-  connection_type = usb;
-  usbpid = 0x2140;
-;
-
-programmer
-  id    = "jtag3isp_edbg";
-  desc  = "Atmel AVR JTAGICE3 in ISP mode, EDBG protocol";
-  type  = "jtagice3_isp";
-  connection_type = usb;
-  usbpid = 0x2140;
+  usbpid = 0x2110, 0x2140;
 ;
 
 programmer
diff --git a/avrftdi.c b/avrftdi.c
index e49ce264..8db292eb 100644
--- a/avrftdi.c
+++ b/avrftdi.c
@@ -41,6 +41,7 @@
 #include "avrpart.h"
 #include "avrftdi_tpi.h"
 #include "avrftdi_private.h"
+#include "usbdevs.h"
 
 #ifndef MAX
 #define MAX(a,b) ((a)>(b)?(a):(b))
@@ -666,12 +667,17 @@ static int avrftdi_open(PROGRAMMER * pgm, char *port)
 	if (pgm->usbvid)
 		vid = pgm->usbvid;
 	else
-		vid = 0x0403;
+		vid = USB_VENDOR_FTDI;
 
-	if (pgm->usbpid)
-		pid = pgm->usbpid;
-	else
-		pid = 0x6010;
+	LNODEID usbpid = lfirst(pgm->usbpid);
+	if (usbpid) {
+		pid = *(int *)(ldata(usbpid));
+		if (lnext(usbpid))
+			fprintf(stderr,
+				"%s: Warning: using PID 0x%04x, ignoring remaining PIDs in list\n",
+				progname, pid);
+	} else
+		pid = USB_DEVICE_FT2232;
 
 	if (0 == pgm->usbsn[0]) /* we don't care about SN. Use first avail. */
 		serial = NULL;
diff --git a/config_gram.y b/config_gram.y
index c0e9e014..44f33716 100644
--- a/config_gram.y
+++ b/config_gram.y
@@ -515,12 +515,7 @@ prog_parm_usb:
       free_token($3);
     }
   } |
-  K_USBPID TKN_EQUAL TKN_NUMBER {
-    {
-      current_prog->usbpid = $3->value.number;
-      free_token($3);
-    }
-  } |
+  K_USBPID TKN_EQUAL usb_pid_list |
   K_USBSN TKN_EQUAL TKN_STRING {
     {
       strncpy(current_prog->usbsn, $3->value.string, PGM_USBSTRINGLEN);
@@ -544,6 +539,29 @@ prog_parm_usb:
   }
 ;
 
+usb_pid_list:
+  TKN_NUMBER {
+    {
+      int *ip = malloc(sizeof(int));
+      if (ip) {
+        *ip = $1->value.number;
+        ladd(current_prog->usbpid, ip);
+      }
+      free_token($1);
+    }
+  } |
+  usb_pid_list TKN_COMMA TKN_NUMBER {
+    {
+      int *ip = malloc(sizeof(int));
+      if (ip) {
+        *ip = $3->value.number;
+        ladd(current_prog->usbpid, ip);
+      }
+      free_token($3);
+    }
+  }
+;
+
 pin_number_non_empty:
   TKN_NUMBER { assign_pin(pin_name, $1, 0);  }
   |
diff --git a/flip1.c b/flip1.c
index 15e2e3ab..44155ca8 100644
--- a/flip1.c
+++ b/flip1.c
@@ -235,8 +235,16 @@ int flip1_initialize(PROGRAMMER* pgm, AVRPART *part)
    */
 
   vid = (pgm->usbvid != 0) ? pgm->usbvid : USB_VENDOR_ATMEL;
-  pid = (pgm->usbpid != 0) ? pgm->usbpid : part->usbpid;
-
+  LNODEID usbpid = lfirst(pgm->usbpid);
+  if (usbpid) {
+    pid = *(int *)(ldata(usbpid));
+    if (lnext(usbpid))
+      fprintf(stderr,
+	      "%s: Warning: using PID 0x%04x, ignoring remaining PIDs in list\n",
+	      progname, pid);
+  } else {
+    pid = part->usbpid;
+  }
   if (!ovsigck && (part->flags & AVRPART_HAS_PDI)) {
     fprintf(stderr,
             "%s: \"flip1\" (FLIP protocol version 1) is for AT90USB* and ATmega*U* devices.\n"
diff --git a/flip2.c b/flip2.c
index fae88554..8ce293ad 100644
--- a/flip2.c
+++ b/flip2.c
@@ -229,7 +229,16 @@ int flip2_initialize(PROGRAMMER* pgm, AVRPART *part)
    */
 
   vid = (pgm->usbvid != 0) ? pgm->usbvid : USB_VENDOR_ATMEL;
-  pid = (pgm->usbpid != 0) ? pgm->usbpid : part->usbpid;
+  LNODEID usbpid = lfirst(pgm->usbpid);
+  if (usbpid) {
+    pid = *(int *)(ldata(usbpid));
+    if (lnext(usbpid))
+      fprintf(stderr,
+	      "%s: Warning: using PID 0x%04x, ignoring remaining PIDs in list\n",
+	      progname, pid);
+  } else {
+    pid = part->usbpid;
+  }
 
   if (!ovsigck && !(part->flags & AVRPART_HAS_PDI)) {
     fprintf(stderr,
diff --git a/ft245r.c b/ft245r.c
index 2bcb7878..5a85d7e5 100644
--- a/ft245r.c
+++ b/ft245r.c
@@ -68,6 +68,7 @@
 #include "config.h"
 #include "bitbang.h"
 #include "ft245r.h"
+#include "usbdevs.h"
 
 #if defined(_WIN32)
 #include <windows.h>
@@ -557,9 +558,20 @@ static int ft245r_open(PROGRAMMER * pgm, char * port) {
 
     handle = malloc (sizeof (struct ftdi_context));
     ftdi_init(handle);
+    LNODEID usbpid = lfirst(pgm->usbpid);
+    int pid;
+    if (usbpid) {
+      pid = *(int *)(ldata(usbpid));
+      if (lnext(usbpid))
+	fprintf(stderr,
+		"%s: Warning: using PID 0x%04x, ignoring remaining PIDs in list\n",
+		progname, pid);
+    } else {
+      pid = USB_DEVICE_FT245;
+    }
     rv = ftdi_usb_open_desc_index(handle,
-                                  pgm->usbvid?pgm->usbvid:0x0403,
-                                  pgm->usbpid?pgm->usbpid:0x6001,
+                                  pgm->usbvid?pgm->usbvid:USB_VENDOR_FTDI,
+                                  pid,
                                   pgm->usbproduct[0]?pgm->usbproduct:NULL,
                                   pgm->usbsn[0]?pgm->usbsn:NULL,
                                   devnum);
diff --git a/jtag3.c b/jtag3.c
index f34f6e37..e7745070 100644
--- a/jtag3.c
+++ b/jtag3.c
@@ -1279,43 +1279,58 @@ static int jtag3_parseextparms(PROGRAMMER * pgm, LISTID extparms)
   return rv;
 }
 
-
-static int jtag3_open(PROGRAMMER * pgm, char * port)
+int jtag3_open_common(PROGRAMMER * pgm, char * port)
 {
   union pinfo pinfo;
+  LNODEID usbpid;
+  int rv = -1;
 
-  if (verbose >= 2)
-    fprintf(stderr, "%s: jtag3_open()\n", progname);
+#if !defined(HAVE_LIBUSB)
+  fprintf(stderr, "avrdude was compiled without usb support.\n");
+  return -1;
+#endif
 
-  /*
-   * The serial_open() function for USB overrides
-   * the meaning of the "baud" parameter to be the USB device ID to
-   * search for.
-   */
-  if (strncmp(port, "usb", 3) == 0) {
-#if defined(HAVE_LIBUSB)
-    serdev = &usb_serdev_frame;
-    if (pgm->usbvid)
-      pinfo.usbinfo.vid = pgm->usbvid;
-    else
-      pinfo.usbinfo.vid = USB_VENDOR_ATMEL;
-    pinfo.usbinfo.flags = 0;
-    if (pgm->usbpid)
-      pinfo.usbinfo.pid = pgm->usbpid;
-    else
-      pinfo.usbinfo.pid = USB_DEVICE_JTAGICE3;
+  if (strncmp(port, "usb", 3) != 0) {
+    fprintf(stderr,
+            "%s: jtag3_open_common(): JTAGICE3/EDBG port names must start with \"usb\"\n",
+            progname);
+    return -1;
+  }
+
+  serdev = &usb_serdev_frame;
+  if (pgm->usbvid)
+    pinfo.usbinfo.vid = pgm->usbvid;
+  else
+    pinfo.usbinfo.vid = USB_VENDOR_ATMEL;
+
+  /* If the config entry did not specify a USB PID, insert the default one. */
+  if (lfirst(pgm->usbpid) == NULL)
+    ladd(pgm->usbpid, (void *)USB_DEVICE_JTAGICE3);
+
+  for (usbpid = lfirst(pgm->usbpid); rv < 0 && usbpid != NULL; usbpid = lnext(usbpid)) {
+    pinfo.usbinfo.flags = PINFO_FL_SILENT;
+    pinfo.usbinfo.pid = *(int *)(ldata(usbpid));
     pgm->fd.usb.max_xfer = USBDEV_MAX_XFER_3;
     pgm->fd.usb.rep = USBDEV_BULK_EP_READ_3;
     pgm->fd.usb.wep = USBDEV_BULK_EP_WRITE_3;
     pgm->fd.usb.eep = USBDEV_EVT_EP_READ_3;
-#else
-    fprintf(stderr, "avrdude was compiled without usb support.\n");
-    return -1;
-#endif
-  }
 
-  strcpy(pgm->port, port);
-  if (serial_open(port, pinfo, &pgm->fd)==-1) {
+    strcpy(pgm->port, port);
+    rv = serial_open(port, pinfo, &pgm->fd);
+  }
+  if (rv < 0) {
+    fprintf(stderr,
+            "%s: jtag3_open_common(): Did not find any device matching VID 0x%04x and PID list: ",
+            progname, (unsigned)pinfo.usbinfo.vid);
+    int notfirst = 0;
+    for (usbpid = lfirst(pgm->usbpid); usbpid != NULL; usbpid = lnext(usbpid)) {
+      if (notfirst)
+        fprintf(stderr, ", ");
+      fprintf(stderr, "0x%04x", (unsigned int)(*(int *)(ldata(usbpid))));
+      notfirst = 1;
+    }
+    fputc('\n', stderr);
+
     return -1;
   }
 
@@ -1335,6 +1350,19 @@ static int jtag3_open(PROGRAMMER * pgm, char * port)
    */
   jtag3_drain(pgm, 0);
 
+  return 0;
+}
+
+
+
+static int jtag3_open(PROGRAMMER * pgm, char * port)
+{
+  if (verbose >= 2)
+    fprintf(stderr, "%s: jtag3_open()\n", progname);
+
+  if (jtag3_open_common(pgm, port) < 0)
+    return -1;
+
   if (jtag3_getsync(pgm, PARM3_CONN_JTAG) < 0)
     return -1;
 
@@ -1343,58 +1371,11 @@ static int jtag3_open(PROGRAMMER * pgm, char * port)
 
 static int jtag3_open_dw(PROGRAMMER * pgm, char * port)
 {
-  union pinfo pinfo;
-
   if (verbose >= 2)
     fprintf(stderr, "%s: jtag3_open_dw()\n", progname);
 
-  /*
-   * The serial_open() function for USB overrides
-   * the meaning of the "baud" parameter to be the USB device ID to
-   * search for.
-   */
-  if (strncmp(port, "usb", 3) == 0) {
-#if defined(HAVE_LIBUSB)
-    serdev = &usb_serdev_frame;
-    if (pgm->usbvid)
-      pinfo.usbinfo.vid = pgm->usbvid;
-    else
-      pinfo.usbinfo.vid = USB_VENDOR_ATMEL;
-    pinfo.usbinfo.flags = 0;
-    if (pgm->usbpid)
-      pinfo.usbinfo.pid = pgm->usbpid;
-    else
-      pinfo.usbinfo.pid = USB_DEVICE_JTAGICE3;
-    pgm->fd.usb.max_xfer = USBDEV_MAX_XFER_3;
-    pgm->fd.usb.rep = USBDEV_BULK_EP_READ_3;
-    pgm->fd.usb.wep = USBDEV_BULK_EP_WRITE_3;
-    pgm->fd.usb.eep = USBDEV_EVT_EP_READ_3;
-#else
-    fprintf(stderr, "avrdude was compiled without usb support.\n");
+  if (jtag3_open_common(pgm, port) < 0)
     return -1;
-#endif
-  }
-
-  strcpy(pgm->port, port);
-  if (serial_open(port, pinfo, &pgm->fd)==-1) {
-    return -1;
-  }
-
-  if (pgm->fd.usb.eep == 0)
-  {
-    /* The event EP has been deleted by usb_open(), so we are
-       running on a CMSIS-DAP device, using EDBG protocol */
-    pgm->flag |= PGM_FL_IS_EDBG;
-    if (verbose)
-      fprintf(stderr,
-              "%s: Found CMSIS-DAP compliant device, using EDBG protocol\n",
-              progname);
-  }
-
-  /*
-   * drain any extraneous input
-   */
-  jtag3_drain(pgm, 0);
 
   if (jtag3_getsync(pgm, PARM3_CONN_DW) < 0)
     return -1;
@@ -1404,58 +1385,11 @@ static int jtag3_open_dw(PROGRAMMER * pgm, char * port)
 
 static int jtag3_open_pdi(PROGRAMMER * pgm, char * port)
 {
-  union pinfo pinfo;
-
   if (verbose >= 2)
     fprintf(stderr, "%s: jtag3_open_pdi()\n", progname);
 
-  /*
-   * The serial_open() function for USB overrides
-   * the meaning of the "baud" parameter to be the USB device ID to
-   * search for.
-   */
-  if (strncmp(port, "usb", 3) == 0) {
-#if defined(HAVE_LIBUSB)
-    serdev = &usb_serdev_frame;
-    if (pgm->usbvid)
-      pinfo.usbinfo.vid = pgm->usbvid;
-    else
-      pinfo.usbinfo.vid = USB_VENDOR_ATMEL;
-    pinfo.usbinfo.flags = 0;
-    if (pgm->usbpid)
-      pinfo.usbinfo.pid = pgm->usbpid;
-    else
-      pinfo.usbinfo.pid = USB_DEVICE_JTAGICE3;
-    pgm->fd.usb.max_xfer = USBDEV_MAX_XFER_3;
-    pgm->fd.usb.rep = USBDEV_BULK_EP_READ_3;
-    pgm->fd.usb.wep = USBDEV_BULK_EP_WRITE_3;
-    pgm->fd.usb.eep = USBDEV_EVT_EP_READ_3;
-#else
-    fprintf(stderr, "avrdude was compiled without usb support.\n");
+  if (jtag3_open_common(pgm, port) < 0)
     return -1;
-#endif
-  }
-
-  strcpy(pgm->port, port);
-  if (serial_open(port, pinfo, &pgm->fd)==-1) {
-    return -1;
-  }
-
-  if (pgm->fd.usb.eep == 0)
-  {
-    /* The event EP has been deleted by usb_open(), so we are
-       running on a CMSIS-DAP device, using EDBG protocol */
-    pgm->flag |= PGM_FL_IS_EDBG;
-    if (verbose)
-      fprintf(stderr,
-              "%s: Found CMSIS-DAP compliant device, using EDBG protocol\n",
-              progname);
-  }
-
-  /*
-   * drain any extraneous input
-   */
-  jtag3_drain(pgm, 0);
 
   if (jtag3_getsync(pgm, PARM3_CONN_PDI) < 0)
     return -1;
diff --git a/jtag3.h b/jtag3.h
index fba0d81e..fef3be01 100644
--- a/jtag3.h
+++ b/jtag3.h
@@ -25,6 +25,7 @@
 extern "C" {
 #endif
 
+int  jtag3_open_common(PROGRAMMER * pgm, char * port);
 int  jtag3_send(PROGRAMMER * pgm, unsigned char * data, size_t len);
 int  jtag3_recv(PROGRAMMER * pgm, unsigned char **msg);
 void jtag3_close(PROGRAMMER * pgm);
diff --git a/pgm.c b/pgm.c
index 72154ad7..9df4ba63 100644
--- a/pgm.c
+++ b/pgm.c
@@ -76,6 +76,7 @@ PROGRAMMER * pgm_new(void)
   memset(pgm, 0, sizeof(*pgm));
 
   pgm->id = lcreat(NULL, 0);
+  pgm->usbpid = lcreat(NULL, 0);
   pgm->desc[0] = 0;
   pgm->type[0] = 0;
   pgm->config_file[0] = 0;
diff --git a/pgm.h b/pgm.h
index e7d4191b..af0cf52a 100644
--- a/pgm.h
+++ b/pgm.h
@@ -76,7 +76,8 @@ typedef struct programmer_t {
   int ppidata;
   int ppictrl;
   int baudrate;
-  int usbvid, usbpid;
+  int usbvid;
+  LISTID usbpid;
   char usbdev[PGM_USBSTRINGLEN], usbsn[PGM_USBSTRINGLEN];
   char usbvendor[PGM_USBSTRINGLEN], usbproduct[PGM_USBSTRINGLEN];
   double bitclock;    /* JTAG ICE clock period in microseconds */
diff --git a/serial.h b/serial.h
index 29f73bcf..a814818d 100644
--- a/serial.h
+++ b/serial.h
@@ -54,6 +54,7 @@ union pinfo
     unsigned short pid;
     unsigned short flags;
 #define PINFO_FL_USEHID         0x0001
+#define PINFO_FL_SILENT         0x0002  /* don't complain if not found */
   } usbinfo;
 };
 
diff --git a/stk500v2.c b/stk500v2.c
index d9ca5e8f..a37960b1 100644
--- a/stk500v2.c
+++ b/stk500v2.c
@@ -602,8 +602,13 @@ static int stk500v2_jtag3_recv(PROGRAMMER * pgm, unsigned char *msg,
             progname);
     return -1;
   }
+  /* Getting more data than expected is a normal case for the EDBG
+     implementation of JTAGICE3, as they always request a full 512
+     octets from the ICE.  Thus, only complain at high verbose
+     levels. */
   if (rv - 1 > maxsize) {
-    fprintf(stderr,
+    if (verbose > 2)
+      fprintf(stderr,
             "%s: stk500v2_jtag3_recv(): got %u bytes, have only room for %u bytes\n",
             progname, (unsigned)rv - 1, (unsigned)maxsize);
     rv = maxsize;
@@ -3662,43 +3667,14 @@ static int stk500v2_dragon_hv_open(PROGRAMMER * pgm, char * port)
  */
 static int stk500v2_jtag3_open(PROGRAMMER * pgm, char * port)
 {
-  union pinfo pinfo;
   void *mycookie;
   int rv;
 
   if (verbose >= 2)
     fprintf(stderr, "%s: stk500v2_jtag3_open()\n", progname);
 
-  /*
-   * The serial_open() function for USB overrides
-   * the meaning of the "baud" parameter to be the USB device ID to
-   * search for.
-   */
-  if (strncmp(port, "usb", 3) == 0) {
-#if defined(HAVE_LIBUSB)
-    serdev = &usb_serdev_frame;
-    pinfo.usbinfo.vid = USB_VENDOR_ATMEL;
-    pinfo.usbinfo.flags = 0;
-    pinfo.usbinfo.pid = USB_DEVICE_JTAGICE3;
-    pgm->fd.usb.max_xfer = USBDEV_MAX_XFER_3;
-    pgm->fd.usb.rep = USBDEV_BULK_EP_READ_3;
-    pgm->fd.usb.wep = USBDEV_BULK_EP_WRITE_3;
-    pgm->fd.usb.eep = USBDEV_EVT_EP_READ_3;
-#else
-    fprintf(stderr, "avrdude was compiled without usb support.\n");
+  if (jtag3_open_common(pgm, port) < 0)
     return -1;
-#endif
-  }
-
-  strcpy(pgm->port, port);
-  if (serial_open(port, pinfo, &pgm->fd)==-1) {
-    return -1;
-  }
-
-  /*
-   * drain any extraneous input
-   */
-  stk500v2_drain(pgm, 0);
 
   mycookie = pgm->cookie;
   pgm->cookie = PDATA(pgm)->chained_pdata;
diff --git a/usb_libusb.c b/usb_libusb.c
index 9c2c9a96..3fe6262f 100644
--- a/usb_libusb.c
+++ b/usb_libusb.c
@@ -310,8 +310,10 @@ static int usbdev_open(char * port, union pinfo pinfo, union filedescriptor *fd)
 	}
     }
 
-  fprintf(stderr, "%s: usbdev_open(): did not find any%s USB device \"%s\"\n",
-	  progname, serno? " (matching)": "", port);
+  if ((pinfo.usbinfo.flags & PINFO_FL_SILENT) == 0 || verbose > 0)
+      fprintf(stderr, "%s: usbdev_open(): did not find any%s USB device \"%s\" (0x%04x:0x%04x)\n",
+	      progname, serno? " (matching)": "", port,
+	      (unsigned)pinfo.usbinfo.vid, (unsigned)pinfo.usbinfo.pid);
   return -1;
 }
 
diff --git a/usbasp.c b/usbasp.c
index c6336ce1..d24d8110 100644
--- a/usbasp.c
+++ b/usbasp.c
@@ -38,6 +38,7 @@
 #include "avr.h"
 #include "pgm.h"
 #include "usbasp.h"
+#include "usbdevs.h"
 
 #if defined(HAVE_LIBUSB) || defined(HAVE_LIBUSB_1_0)
 
@@ -464,8 +465,19 @@ static int usbasp_open(PROGRAMMER * pgm, char * port)
 	    progname, port);
 
   /* usb_init will be done in usbOpenDevice */
-  if (usbOpenDevice(&PDATA(pgm)->usbhandle, pgm->usbvid, pgm->usbvendor,
-		  pgm->usbpid, pgm->usbproduct) != 0) {
+  LNODEID usbpid = lfirst(pgm->usbpid);
+  int pid, vid;
+  if (usbpid) {
+    pid = *(int *)(ldata(usbpid));
+    if (lnext(usbpid))
+      fprintf(stderr,
+	      "%s: Warning: using PID 0x%04x, ignoring remaining PIDs in list\n",
+	      progname, pid);
+  } else {
+    pid = USBASP_SHARED_PID;
+  }
+  vid = pgm->usbvid? pgm->usbvid: USBASP_SHARED_VID;
+  if (usbOpenDevice(&PDATA(pgm)->usbhandle, vid, pgm->usbvendor, pid, pgm->usbproduct) != 0) {
     /* try alternatives */
     if(strcasecmp(ldata(lfirst(pgm->id)), "usbasp") == 0) {
     /* for id usbasp autodetect some variants */
@@ -500,7 +512,7 @@ static int usbasp_open(PROGRAMMER * pgm, char * port)
 
     fprintf(stderr,
             "%s: error: could not find USB device with vid=0x%x pid=0x%x",
-            progname, pgm->usbvid, pgm->usbpid);
+            progname, vid, pid);
     if (pgm->usbvendor[0] != 0) {
        fprintf(stderr, " vendor='%s'", pgm->usbvendor);
     }
diff --git a/usbasp.h b/usbasp.h
index b94ba0a2..98e300da 100644
--- a/usbasp.h
+++ b/usbasp.h
@@ -23,16 +23,6 @@
 
 #include "avrpart.h"
 
-/* USB identifiers */
-#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_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
diff --git a/usbdevs.h b/usbdevs.h
index 5bf91fdb..62950fb2 100644
--- a/usbdevs.h
+++ b/usbdevs.h
@@ -34,6 +34,27 @@
 #define USB_DEVICE_XPLAINEDPRO 0x2111
 #define USB_DEVICE_JTAG3_EDBG  0x2140
 
+#define USB_VENDOR_FTDI        0x0403
+#define USB_DEVICE_FT2232      0x6010
+#define USB_DEVICE_FT245       0x6001
+
+#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_NIBOBEE_VID  0x16C0  /* VOTI */
+#define	USBASP_NIBOBEE_PID  0x092F  /* NIBObee PID */
+
+// these are specifically assigned to USBtiny,
+// if you need your own VID and PIDs you can get them for cheap from
+// www.mecanique.co.uk so please don't reuse these. Thanks!
+#define USBTINY_VENDOR_DEFAULT  0x1781
+#define USBTINY_PRODUCT_DEFAULT 0x0C9F
+
+
+
 /* JTAGICEmkII, AVRISPmkII */
 #define USBDEV_BULK_EP_WRITE_MKII 0x02
 #define USBDEV_BULK_EP_READ_MKII  0x82
diff --git a/usbtiny.c b/usbtiny.c
index ff2597f3..76d5c3d1 100644
--- a/usbtiny.c
+++ b/usbtiny.c
@@ -37,6 +37,7 @@
 #include "pgm.h"
 #include "config.h"
 #include "usbtiny.h"
+#include "usbdevs.h"
 
 #if defined(HAVE_LIBUSB)      // we use LIBUSB to talk to the board
 #if defined(HAVE_USB_H)
@@ -230,11 +231,17 @@ static	int	usbtiny_open(PROGRAMMER* pgm, char* name)
     vid = pgm->usbvid;
   else
     vid = USBTINY_VENDOR_DEFAULT;
-  
-  if (pgm->usbpid)
-    pid = pgm->usbpid;
-  else
+
+  LNODEID usbpid = lfirst(pgm->usbpid);
+  if (usbpid) {
+    pid = *(int *)(ldata(usbpid));
+    if (lnext(usbpid))
+      fprintf(stderr,
+	      "%s: Warning: using PID 0x%04x, ignoring remaining PIDs in list\n",
+	      progname, pid);
+  } else {
     pid = USBTINY_PRODUCT_DEFAULT;
+  }
   
 
   // now we iterate through all the busses and devices
diff --git a/usbtiny.h b/usbtiny.h
index 1bf49fc2..5cae7e5c 100644
--- a/usbtiny.h
+++ b/usbtiny.h
@@ -22,11 +22,6 @@
 
 #include "avrpart.h"
 
-// these are specifically assigned to USBtiny,
-// if you need your own VID and PIDs you can get them for cheap from
-// www.mecanique.co.uk so please don't reuse these. Thanks!
-#define USBTINY_VENDOR_DEFAULT  0x1781
-#define USBTINY_PRODUCT_DEFAULT 0x0C9F
 
 // Generic requests to the USBtiny
 #define	USBTINY_ECHO 	     0      // echo test