diff --git a/avrdude/ChangeLog b/avrdude/ChangeLog
index 86b20a25..3250d64f 100644
--- a/avrdude/ChangeLog
+++ b/avrdude/ChangeLog
@@ -1,3 +1,16 @@
+2005-06-19  Joerg Wunsch <j@uriah.heep.sax.de>
+
+	* Makefile.am: Implement libusb-base USB transport for the
+	JTAG ICE mkII.
+	* configure.ac: ditto.
+	* jtagmkII.c: ditto.
+	* ser_posix.c: ditto.
+	* ser_win32.c: ditto.
+	* serial.h: ditto.
+	* usb_libusb.c: ditto (New file).
+	* avrdude.1: document the USB transport.
+	* doc/avrdude.texi: ditto.
+
 2005-06-15  Joerg Wunsch <j@uriah.heep.sax.de>
 
 	* avrdude.conf.in: The AT90CAN128 has AllowFullPageBitstream = no.
diff --git a/avrdude/Makefile.am b/avrdude/Makefile.am
index 8221f36b..9ca2895e 100644
--- a/avrdude/Makefile.am
+++ b/avrdude/Makefile.am
@@ -94,7 +94,8 @@ avrdude_SOURCES = \
 	stk500v2.h \
 	stk500v2_private.h \
 	term.c \
-	term.h
+	term.h \
+	usb_libusb.c
 
 man_MANS = avrdude.1
 
diff --git a/avrdude/avrdude.1 b/avrdude/avrdude.1
index d92716ae..ba7f6e78 100644
--- a/avrdude/avrdude.1
+++ b/avrdude/avrdude.1
@@ -303,6 +303,23 @@ serial port, the
 .Pa /dev/cuaa0
 port is the default.  If you need to use a different parallel or
 serial port, use this option to specify the alternate port name.
+.Pp
+For the JTAG ICE mkII, if
+.Nm
+has been configured with libusb support,
+.Ar port
+can alternatively be specified as
+.Ar usb Ns Op \&: Ns Ar serialno .
+This will cause
+.Nm
+to search a JTAG ICE mkII on USB.
+If
+.Ar serialno
+is also specified, it will be matched against the serial number read
+from any JTAG ICE mkII found on USB.
+The match is done after stripping any existing colons from the given
+serial number, and right-to-left, so only the least significant bytes
+from the serial number need to be given.
 .It Fl q
 Disable (or quell) output of the progress bar while reading or writing
 to the device.
diff --git a/avrdude/configure.ac b/avrdude/configure.ac
index dd378141..62f1550b 100644
--- a/avrdude/configure.ac
+++ b/avrdude/configure.ac
@@ -44,6 +44,7 @@ AM_PROG_LEX
 AC_CHECK_LIB([termcap], [tputs])
 AC_CHECK_LIB([ncurses], [tputs])
 AC_CHECK_LIB([readline], [readline])
+AC_CHECK_LIB([usb], [usb_open])
 
 # Checks for header files.
 AC_HEADER_STDC
diff --git a/avrdude/doc/avrdude.texi b/avrdude/doc/avrdude.texi
index afd61ab6..375ebe87 100644
--- a/avrdude/doc/avrdude.texi
+++ b/avrdude/doc/avrdude.texi
@@ -488,6 +488,15 @@ used. See Appendix A, Platform Dependent Information, to find out the
 default port names for your platform. If you need to use a different
 parallel or serial port, use this option to specify the alternate port name.
 
+For the JTAG ICE mkII, if AVRDUDE has been built with libusb support,
+@var{port} may alternatively be specified as
+@var{usb}[:@var{serialno}].  In that case, the JTAG ICE mkII will be
+looked up on USB.  If @var{serialno} is also specified, it will be
+matched against the serial number read from any JTAG ICE mkII found on
+USB.  The match is done after stripping any existing colons from the
+given serial number, and right-to-left, so only the least significant
+bytes from the serial number need to be given.
+
 @item -q
 Disable (or quell) output of the progress bar while reading or writing
 to the device.
@@ -594,6 +603,7 @@ should not be used.
 
 @end table
 
+@page
 @c
 @c Node
 @c
@@ -642,6 +652,7 @@ avrdude done.  Thank you.
 @end cartouche
 @end example
 
+@page
 @noindent
 Upload the flash memory from the ATmega128 connected to the STK500
 programmer and save it in raw binary format in the file named
@@ -670,6 +681,7 @@ avrdude done.  Thank you.
 @end cartouche
 @end example
 
+@page
 @noindent
 Using the default programmer, download the file @code{diag.hex} to
 flash, @code{eeprom.hex} to EEPROM, and set the Extended, High, and Low
@@ -718,6 +730,29 @@ avrdude done.  Thank you.
 @end cartouche
 @end example
 
+@page
+@noindent
+Connect to the JTAG ICE mkII which serial number ends up in 1C37 via
+USB, and enter terminal mode:
+
+@example
+@cartouche
+
+% avrdude -c jtag2 -p m649 -P usb:1c:37 -t
+
+avrdude: AVR device initialized and ready to accept instructions
+
+Reading | ################################################## | 100% 0.03s
+
+avrdude: Device signature = 0x1e9603
+
+[ ... terminal mode output skipped for brevity ... ]
+
+avrdude done.  Thank you.
+
+@end cartouche
+@end example
+
 
 
 @c
diff --git a/avrdude/jtagmkII.c b/avrdude/jtagmkII.c
index b8f81b32..ea7fe2a7 100644
--- a/avrdude/jtagmkII.c
+++ b/avrdude/jtagmkII.c
@@ -1047,6 +1047,15 @@ static int jtagmkII_open(PROGRAMMER * pgm, char * port)
   if (verbose >= 2)
     fprintf(stderr, "%s: jtagmkII_open()\n", progname);
 
+#if defined(HAVE_LIBUSB)
+  /*
+   * If the port name starts with "usb", divert the serial routines
+   * to the USB ones.
+   */
+  if (strncmp(port, "usb", 3) == 0)
+    serdev = &usb_serdev;
+#endif
+
   strcpy(pgm->port, port);
   /*
    * The JTAG ICE mkII always starts with a baud rate of 19200 Bd upon
diff --git a/avrdude/ser_posix.c b/avrdude/ser_posix.c
index b8b6986e..47f2ab5c 100644
--- a/avrdude/ser_posix.c
+++ b/avrdude/ser_posix.c
@@ -38,6 +38,8 @@
 #include <termios.h>
 #include <unistd.h>
 
+#include "serial.h"
+
 extern char *progname;
 extern int verbose;
 
@@ -78,7 +80,7 @@ static speed_t serial_baud_lookup(long baud)
   exit(1);
 }
 
-int serial_setspeed(int fd, long baud)
+static int ser_setspeed(int fd, long baud)
 {
   int rc;
   struct termios termios;
@@ -92,7 +94,7 @@ int serial_setspeed(int fd, long baud)
    */
   rc = tcgetattr(fd, &termios);
   if (rc < 0) {
-    fprintf(stderr, "%s: serial_setspeed(): tcgetattr() failed, %s", 
+    fprintf(stderr, "%s: ser_setspeed(): tcgetattr() failed, %s", 
             progname, strerror(errno));
     return -errno;
   }
@@ -110,7 +112,7 @@ int serial_setspeed(int fd, long baud)
   
   rc = tcsetattr(fd, TCSANOW, &termios);
   if (rc < 0) {
-    fprintf(stderr, "%s: serial_setspeed(): tcsetattr() failed, %s", 
+    fprintf(stderr, "%s: ser_setspeed(): tcsetattr() failed, %s", 
             progname, strerror(errno));
     return -errno;
   }
@@ -127,7 +129,7 @@ int serial_setspeed(int fd, long baud)
 }
 
 
-int serial_open(char * port, int baud)
+static int ser_open(char * port, long baud)
 {
   int rc;
   int fd;
@@ -137,7 +139,7 @@ int serial_open(char * port, int baud)
    */
   fd = open(port, O_RDWR | O_NOCTTY /*| O_NONBLOCK*/);
   if (fd < 0) {
-    fprintf(stderr, "%s: serial_open(): can't open device \"%s\": %s\n",
+    fprintf(stderr, "%s: ser_open(): can't open device \"%s\": %s\n",
             progname, port, strerror(errno));
     exit(1);
   }
@@ -145,10 +147,10 @@ int serial_open(char * port, int baud)
   /*
    * set serial line attributes
    */
-  rc = serial_setspeed(fd, baud);
+  rc = ser_setspeed(fd, baud);
   if (rc) {
     fprintf(stderr, 
-            "%s: serial_open(): can't set attributes for device \"%s\"\n",
+            "%s: ser_open(): can't set attributes for device \"%s\"\n",
             progname, port);
     exit(1);
   }
@@ -157,7 +159,7 @@ int serial_open(char * port, int baud)
 }
 
 
-void serial_close(int fd)
+static void ser_close(int fd)
 {
   /* FIXME: Should really restore the terminal to original state here. */
 
@@ -165,7 +167,7 @@ void serial_close(int fd)
 }
 
 
-int serial_send(int fd, char * buf, size_t buflen)
+static int ser_send(int fd, char * buf, size_t buflen)
 {
   struct timeval timeout, to2;
   fd_set wfds;
@@ -212,7 +214,7 @@ int serial_send(int fd, char * buf, size_t buflen)
     if (nfds == 0) {
       if (verbose >= 1)
 	fprintf(stderr,
-		"%s: serial_send(): programmer is not responding\n",
+		"%s: ser_send(): programmer is not responding\n",
 		progname);
       exit(1);
     }
@@ -221,7 +223,7 @@ int serial_send(int fd, char * buf, size_t buflen)
         goto reselect;
       }
       else {
-        fprintf(stderr, "%s: serial_send(): select(): %s\n",
+        fprintf(stderr, "%s: ser_send(): select(): %s\n",
                 progname, strerror(errno));
         exit(1);
       }
@@ -229,7 +231,7 @@ int serial_send(int fd, char * buf, size_t buflen)
 
     rc = write(fd, p, (len > 1024) ? 1024 : len);
     if (rc < 0) {
-      fprintf(stderr, "%s: serial_send(): write error: %s\n",
+      fprintf(stderr, "%s: ser_send(): write error: %s\n",
               progname, strerror(errno));
       exit(1);
     }
@@ -241,7 +243,7 @@ int serial_send(int fd, char * buf, size_t buflen)
 }
 
 
-int serial_recv(int fd, char * buf, size_t buflen)
+static int ser_recv(int fd, char * buf, size_t buflen)
 {
   struct timeval timeout, to2;
   fd_set rfds;
@@ -264,19 +266,19 @@ int serial_recv(int fd, char * buf, size_t buflen)
     if (nfds == 0) {
       if (verbose > 1)
 	fprintf(stderr,
-		"%s: serial_recv(): programmer is not responding\n",
+		"%s: ser_recv(): programmer is not responding\n",
 		progname);
       return -1;
     }
     else if (nfds == -1) {
       if (errno == EINTR || errno == EAGAIN) {
 	fprintf(stderr,
-		"%s: serial_recv(): programmer is not responding,reselecting\n",
+		"%s: ser_recv(): programmer is not responding,reselecting\n",
 		progname);
         goto reselect;
       }
       else {
-        fprintf(stderr, "%s: serial_recv(): select(): %s\n",
+        fprintf(stderr, "%s: ser_recv(): select(): %s\n",
                 progname, strerror(errno));
         exit(1);
       }
@@ -284,7 +286,7 @@ int serial_recv(int fd, char * buf, size_t buflen)
 
     rc = read(fd, p, (buflen - len > 1024) ? 1024 : buflen - len);
     if (rc < 0) {
-      fprintf(stderr, "%s: serial_recv(): read error: %s\n",
+      fprintf(stderr, "%s: ser_recv(): read error: %s\n",
               progname, strerror(errno));
       exit(1);
     }
@@ -318,7 +320,7 @@ int serial_recv(int fd, char * buf, size_t buflen)
 }
 
 
-int serial_drain(int fd, int display)
+static int ser_drain(int fd, int display)
 {
   struct timeval timeout;
   fd_set rfds;
@@ -351,7 +353,7 @@ int serial_drain(int fd, int display)
         goto reselect;
       }
       else {
-        fprintf(stderr, "%s: serial_drain(): select(): %s\n",
+        fprintf(stderr, "%s: ser_drain(): select(): %s\n",
                 progname, strerror(errno));
         exit(1);
       }
@@ -359,7 +361,7 @@ int serial_drain(int fd, int display)
 
     rc = read(fd, &buf, 1);
     if (rc < 0) {
-      fprintf(stderr, "%s: serial_drain(): read error: %s\n",
+      fprintf(stderr, "%s: ser_drain(): read error: %s\n",
               progname, strerror(errno));
       exit(1);
     }
@@ -371,4 +373,16 @@ int serial_drain(int fd, int display)
   return 0;
 }
 
+struct serial_device serial_serdev =
+{
+  .open = ser_open,
+  .setspeed = ser_setspeed,
+  .close = ser_close,
+  .send = ser_send,
+  .recv = ser_recv,
+  .drain = ser_drain,
+};
+
+struct serial_device *serdev = &serial_serdev;
+
 #endif  /* WIN32NATIVE */
diff --git a/avrdude/ser_win32.c b/avrdude/ser_win32.c
index 2bd72ef5..3b21a2aa 100644
--- a/avrdude/ser_win32.c
+++ b/avrdude/ser_win32.c
@@ -72,7 +72,7 @@ static DWORD serial_baud_lookup(long baud)
 }
 
 
-BOOL serial_w32SetTimeOut(HANDLE hComPort, DWORD timeout) // in ms
+static BOOL serial_w32SetTimeOut(HANDLE hComPort, DWORD timeout) // in ms
 {
 	COMMTIMEOUTS ctmo;
 	ZeroMemory (&ctmo, sizeof(COMMTIMEOUTS));
@@ -83,7 +83,7 @@ BOOL serial_w32SetTimeOut(HANDLE hComPort, DWORD timeout) // in ms
 	return SetCommTimeouts(hComPort, &ctmo);
 }
 
-int serial_setspeed(int fd, long baud)
+static int ser_setspeed(int fd, long baud)
 {
 	DCB dcb;
 	HANDLE hComPort = (HANDLE)fd;
@@ -105,13 +105,13 @@ int serial_setspeed(int fd, long baud)
 }
 
 
-int serial_open(char * port, long baud)
+static int ser_open(char * port, long baud)
 {
 	LPVOID lpMsgBuf;
 	HANDLE hComPort=INVALID_HANDLE_VALUE;
 
 	/* if (hComPort!=INVALID_HANDLE_VALUE) 
-		fprintf(stderr, "%s: serial_open(): \"%s\" is already open\n",
+		fprintf(stderr, "%s: ser_open(): \"%s\" is already open\n",
 				progname, port);
 	*/
 
@@ -129,7 +129,7 @@ int serial_open(char * port, long baud)
 			(LPTSTR) &lpMsgBuf,
 			0,
 			NULL);
-		fprintf(stderr, "%s: serial_open(): can't open device \"%s\": %s\n",
+		fprintf(stderr, "%s: ser_open(): can't open device \"%s\": %s\n",
 				progname, port, (char*)lpMsgBuf);
 		LocalFree( lpMsgBuf );
 		exit(1);
@@ -138,16 +138,16 @@ int serial_open(char * port, long baud)
 	if (!SetupComm(hComPort, W32SERBUFSIZE, W32SERBUFSIZE))
 	{
 		CloseHandle(hComPort);
-		fprintf(stderr, "%s: serial_open(): can't set buffers for \"%s\"\n",
+		fprintf(stderr, "%s: ser_open(): can't set buffers for \"%s\"\n",
 				progname, port);
 		exit(1);
 	}
 
 
-	if (serial_setspeed((int)hComPort, baud) != 0)
+	if (ser_setspeed((int)hComPort, baud) != 0)
 	{
 		CloseHandle(hComPort);
-		fprintf(stderr, "%s: serial_open(): can't set com-state for \"%s\"\n",
+		fprintf(stderr, "%s: ser_open(): can't set com-state for \"%s\"\n",
 				progname, port);
 		exit(1);
 	}
@@ -155,7 +155,7 @@ int serial_open(char * port, long baud)
 	if (!serial_w32SetTimeOut(hComPort,0))
 	{
 		CloseHandle(hComPort);
-		fprintf(stderr, "%s: serial_open(): can't set initial timeout for \"%s\"\n",
+		fprintf(stderr, "%s: ser_open(): can't set initial timeout for \"%s\"\n",
 				progname, port);
 		exit(1);
 	}
@@ -164,7 +164,7 @@ int serial_open(char * port, long baud)
 }
 
 
-void serial_close(int fd)
+static void ser_close(int fd)
 {
 	HANDLE hComPort=(HANDLE)fd;
 	if (hComPort != INVALID_HANDLE_VALUE)
@@ -174,7 +174,7 @@ void serial_close(int fd)
 }
 
 
-int serial_send(int fd, char * buf, size_t buflen)
+static int ser_send(int fd, char * buf, size_t buflen)
 {
 	size_t len = buflen;
 	unsigned char c='\0';
@@ -183,7 +183,7 @@ int serial_send(int fd, char * buf, size_t buflen)
 	HANDLE hComPort=(HANDLE)fd;
 
 	if (hComPort == INVALID_HANDLE_VALUE) {
-		fprintf(stderr, "%s: serial_send(): port not open\n",
+		fprintf(stderr, "%s: ser_send(): port not open\n",
               progname); 
 		exit(1);
 	}
@@ -213,13 +213,13 @@ int serial_send(int fd, char * buf, size_t buflen)
 	serial_w32SetTimeOut(hComPort,500);
 
 	if (!WriteFile (hComPort, buf, buflen, &written, NULL)) {
-		fprintf(stderr, "%s: serial_send(): write error: %s\n",
+		fprintf(stderr, "%s: ser_send(): write error: %s\n",
               progname, "sorry no info avail"); // TODO
 		exit(1);
 	}
 
 	if (written != buflen) {
-		fprintf(stderr, "%s: serial_send(): size/send mismatch\n",
+		fprintf(stderr, "%s: ser_send(): size/send mismatch\n",
               progname); 
 		exit(1);
 	}
@@ -228,7 +228,7 @@ int serial_send(int fd, char * buf, size_t buflen)
 }
 
 
-int serial_recv(int fd, char * buf, size_t buflen)
+static int ser_recv(int fd, char * buf, size_t buflen)
 {
 	unsigned char c;
 	char * p = buf;
@@ -238,7 +238,7 @@ int serial_recv(int fd, char * buf, size_t buflen)
 	HANDLE hComPort=(HANDLE)fd;
 	
 	if (hComPort == INVALID_HANDLE_VALUE) {
-		fprintf(stderr, "%s: serial_read(): port not open\n",
+		fprintf(stderr, "%s: ser_read(): port not open\n",
               progname); 
 		exit(1);
 	}
@@ -257,7 +257,7 @@ int serial_recv(int fd, char * buf, size_t buflen)
 			(LPTSTR) &lpMsgBuf,
 			0,
 			NULL 	);
-		fprintf(stderr, "%s: serial_recv(): read error: %s\n",
+		fprintf(stderr, "%s: ser_recv(): read error: %s\n",
 			      progname, (char*)lpMsgBuf);
 		LocalFree( lpMsgBuf );
 		exit(1);
@@ -288,7 +288,7 @@ int serial_recv(int fd, char * buf, size_t buflen)
 }
 
 
-int serial_drain(int fd, int display)
+static int ser_drain(int fd, int display)
 {
 	// int rc;
 	unsigned char buf[10];
@@ -298,7 +298,7 @@ int serial_drain(int fd, int display)
 	HANDLE hComPort=(HANDLE)fd;
 
   	if (hComPort == INVALID_HANDLE_VALUE) {
-		fprintf(stderr, "%s: serial_drain(): port not open\n",
+		fprintf(stderr, "%s: ser_drain(): port not open\n",
               progname); 
 		exit(1);
 	}
@@ -323,7 +323,7 @@ int serial_drain(int fd, int display)
 				(LPTSTR) &lpMsgBuf,
 				0,
 				NULL 	);
-			fprintf(stderr, "%s: serial_drain(): read error: %s\n",
+			fprintf(stderr, "%s: ser_drain(): read error: %s\n",
 					  progname, (char*)lpMsgBuf);
 			LocalFree( lpMsgBuf );
 			exit(1);
@@ -340,4 +340,16 @@ int serial_drain(int fd, int display)
   return 0;
 }
 
+struct serial_device serial_serdev =
+{
+  .open = ser_open,
+  .setspeed = ser_setspeed,
+  .close = ser_close,
+  .send = ser_send,
+  .recv = ser_recv,
+  .drain = ser_drain,
+};
+
+struct serial_device *serdev = &serial_serdev;
+
 #endif /* WIN32NATIVE */
diff --git a/avrdude/serial.h b/avrdude/serial.h
index c3071d74..5dc8d745 100644
--- a/avrdude/serial.h
+++ b/avrdude/serial.h
@@ -32,12 +32,25 @@
 
 extern long serial_recv_timeout;
 
-extern int serial_open(char * port, long baud);
-extern int serial_setspeed(int fd, long baud);
-extern void serial_close(int fd);
+struct serial_device
+{
+  int (*open)(char * port, long baud);
+  int (*setspeed)(int fd, long baud);
+  void (*close)(int fd);
 
-extern int serial_send(int fd, char * buf, size_t buflen);
-extern int serial_recv(int fd, char * buf, size_t buflen);
-extern int serial_drain(int fd, int display);
+  int (*send)(int fd, char * buf, size_t buflen);
+  int (*recv)(int fd, char * buf, size_t buflen);
+  int (*drain)(int fd, int display);
+};
+
+extern struct serial_device *serdev;
+extern struct serial_device serial_serdev, usb_serdev;
+
+#define serial_open (serdev->open)
+#define serial_setspeed (serdev->setspeed)
+#define serial_close (serdev->close)
+#define serial_send (serdev->send)
+#define serial_recv (serdev->recv)
+#define serial_drain (serdev->drain)
 
 #endif /* __serial_h__ */
diff --git a/avrdude/usb_libusb.c b/avrdude/usb_libusb.c
new file mode 100644
index 00000000..11d493b8
--- /dev/null
+++ b/avrdude/usb_libusb.c
@@ -0,0 +1,268 @@
+/*
+ * avrdude - A Downloader/Uploader for AVR device programmers
+ * Copyright (C) 2005 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
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+/* $Id$ */
+
+/*
+ * USB interface via libusb for avrdude.
+ */
+
+#include "ac_cfg.h"
+#if defined(HAVE_LIBUSB)
+
+
+#include <ctype.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/time.h>
+
+#include <usb.h>
+
+#include "serial.h"
+
+extern char *progname;
+extern int verbose;
+
+#define USB_VENDOR_ATMEL 1003
+#define USB_DEVICE_JTAGICEMKII 0x2103
+/*
+ * Should we query the endpoint number and max transfer size from USB?
+ * After all, the JTAG ICE mkII docs document these values.
+ */
+#define JTAGICE_BULK_EP 2
+#define JTAGICE_MAX_XFER 64
+
+static char usbbuf[JTAGICE_MAX_XFER];
+static int buflen = -1, bufptr;
+
+static int usbdev_open(char * port, long baud)
+{
+  char string[256];
+  struct usb_bus *bus;
+  struct usb_device *dev;
+  usb_dev_handle *udev;
+  char *serno, *cp2;
+  size_t x;
+
+  /*
+   * The syntax for usb devices is defined as:
+   *
+   * -P usb[:serialnumber]
+   *
+   * See if we've got a serial number passed here.  The serial number
+   * might contain colons which we remove below, and we compare it
+   * right-to-left, so only the least significant nibbles need to be
+   * specified.
+   */
+  if ((serno = strchr(port, ':')) != NULL)
+    {
+      /* first, drop all colons there if any */
+      cp2 = ++serno;
+
+      while ((cp2 = strchr(cp2, ':')) != NULL)
+	{
+	  x = strlen(cp2) - 1;
+	  memmove(cp2, cp2 + 1, x);
+	  cp2[x] = '\0';
+	}
+
+      if (strlen(serno) > 12)
+	{
+	  fprintf(stderr,
+		  "%s: usbdev_open(): invalid serial number \"%s\"\n",
+		  progname, serno);
+	  exit(1);
+	}
+    }
+
+  usb_init();
+
+  usb_find_busses();
+  usb_find_devices();
+
+  for (bus = usb_busses; bus; bus = bus->next)
+    {
+      if (bus->root_dev)
+	continue;
+
+      for (dev = bus->devices; dev; dev = dev->next)
+	{
+	  udev = usb_open(dev);
+	  if (udev)
+	    {
+	      if (dev->descriptor.idVendor == USB_VENDOR_ATMEL &&
+		  dev->descriptor.idProduct == USB_DEVICE_JTAGICEMKII)
+		{
+		  /* yeah, we found something */
+		  if (usb_get_string_simple(udev,
+					    dev->descriptor.iSerialNumber,
+					    string, sizeof(string)) < 0)
+		    {
+		      fprintf(stderr,
+			      "%s: usb_open(): cannot read serial number \"%s\"\n",
+			      progname, usb_strerror());
+		      exit(1);
+		    }
+
+		  if (verbose)
+		    fprintf(stderr,
+			    "%s: usb_open(): Found JTAG ICE, serno: %s\n",
+			    progname, string);
+		  if (serno != NULL)
+		    {
+		      /*
+		       * See if the serial number requested by the
+		       * user matches what we found, matching
+		       * right-to-left.
+		       */
+		      x = strlen(string) - strlen(serno);
+		      if (strcasecmp(string + x, serno) != 0)
+			{
+			  if (verbose > 2)
+			    fprintf(stderr,
+				    "%s: usbdev_open(): serial number doesn't match\n",
+				    progname);
+			  usb_close(udev);
+			      continue;
+			}
+		    }
+
+		  return (int)udev;
+		}
+	      usb_close(udev);
+	    }
+	}
+    }
+
+  fprintf(stderr, "%s: usbdev_open(): did not find any%s USB device \"%s\"\n",
+	  progname, serno? " (matching)": "", port);
+  exit(1);
+}
+
+static int usbdev_setspeed(int fd, long baud)
+{
+  return 0;
+}
+
+static void usbdev_close(int fd)
+{
+  usb_dev_handle *udev = (usb_dev_handle *)fd;
+
+  usb_close(udev);
+}
+
+
+static int usbdev_send(int fd, char *bp, size_t mlen)
+{
+  usb_dev_handle *udev = (usb_dev_handle *)fd;
+
+  return usb_bulk_write(udev, JTAGICE_BULK_EP, (char *)bp, mlen, 5000) != mlen;
+}
+
+/*
+ * As calls to usb_bulk_read() result in exactly one USB request, we
+ * have to buffer the read results ourselves, so the single-char read
+ * requests performed by the upper layers will be handled.  In order
+ * to do this, we maintain a private buffer of what we've got so far,
+ * and transparently issue another USB read request if the buffer is
+ * empty and more data are requested.
+ */
+static int
+usb_fill_buf(usb_dev_handle *udev)
+{
+  int rv;
+
+  rv = usb_bulk_read(udev, JTAGICE_BULK_EP, usbbuf, JTAGICE_MAX_XFER, 5000);
+  if (rv < 0)
+    {
+      if (verbose > 1)
+	fprintf(stderr, "%s: usb_fill_buf(): usb_bulk_read() error %s\n",
+		progname, usb_strerror());
+      return -1;
+    }
+
+  buflen = rv;
+  bufptr = 0;
+
+  return 0;
+}
+
+static int usbdev_recv(int fd, char *buf, size_t nbytes)
+{
+  usb_dev_handle *udev = (usb_dev_handle *)fd;
+  int i, amnt;
+  char * p = buf;
+
+  for (i = 0; nbytes > 0;)
+    {
+      if (buflen <= bufptr)
+	{
+	  if (usb_fill_buf(udev) < 0)
+	    return -1;
+	}
+      amnt = buflen - bufptr > nbytes? nbytes: buflen - bufptr;
+      memcpy(buf + i, usbbuf + bufptr, amnt);
+      bufptr += amnt;
+      nbytes -= amnt;
+      i += amnt;
+    }
+
+  if (verbose > 3)
+  {
+      fprintf(stderr, "%s: Recv: ", progname);
+
+      while (i) {
+        unsigned char c = *p;
+        if (isprint(c)) {
+          fprintf(stderr, "%c ", c);
+        }
+        else {
+          fprintf(stderr, ". ");
+        }
+        fprintf(stderr, "[%02x] ", c);
+
+        p++;
+        i--;
+      }
+      fprintf(stderr, "\n");
+  }
+
+  return 0;
+}
+
+
+static int usbdev_drain(int fd, int display)
+{
+  return 0;
+}
+
+struct serial_device usb_serdev =
+{
+  .open = usbdev_open,
+  .setspeed = usbdev_setspeed,
+  .close = usbdev_close,
+  .send = usbdev_send,
+  .recv = usbdev_recv,
+  .drain = usbdev_drain,
+};
+
+#endif  /* HAVE_LIBUSB */