diff --git a/ChangeLog b/ChangeLog
index daea7b05..b3b96431 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,15 @@
+2014-02-26  Joerg Wunsch <j.gnu@uriah.heep.sax.de>
+
+	* jtag3_private.h: Add EDBG/CMSIS-DAP specific constants.
+	* jtag3.c: Add EDBG/CMSIS-DAP protocol implementation.
+	* serial.h: (Dito.)
+	* usbdevs.h: (Dito.)
+	* usb_libusb.c: (Dito.)
+	* configure.ac: (Dito.)
+	* avrdude.conf.in: Add JTAGICE3 and XplainedPro entries using
+	EDBG.
+	* configure.ac: Bump version date.
+
 2014-02-22  Joerg Wunsch <j.gnu@uriah.heep.sax.de>
 
 	* usb_libusb.c (usbdev_recv_frame): Fix a bug where a new recv
diff --git a/NEWS b/NEWS
index 9a09c3c0..1ac31e71 100644
--- a/NEWS
+++ b/NEWS
@@ -8,7 +8,7 @@ Approximate change log for AVRDUDE by version.
 Current:
 
   * Major changes compared to the previous version:
-    - ...
+    - Atmel EDBG protocol support added (JTAGICE3, XplainedPro)
 
   * New devices supported:
     - ...
diff --git a/avrdude.conf.in b/avrdude.conf.in
index b247d644..e6a521bd 100644
--- a/avrdude.conf.in
+++ b/avrdude.conf.in
@@ -994,6 +994,7 @@ programmer
   desc  = "Atmel AVR JTAGICE3 in JTAG mode";
   type  = "jtagice3";
   connection_type = usb;
+  usbpid = 0x2110;
 ;
 
 programmer
@@ -1001,6 +1002,7 @@ programmer
   desc  = "Atmel AVR JTAGICE3 in PDI mode";
   type  = "jtagice3_pdi";
   connection_type = usb;
+  usbpid = 0x2110;
 ;
 
 programmer
@@ -1008,6 +1010,7 @@ programmer
   desc  = "Atmel AVR JTAGICE3 in debugWIRE mode";
   type  = "jtagice3_dw";
   connection_type = usb;
+  usbpid = 0x2110;
 ;
 
 programmer
@@ -1015,6 +1018,47 @@ 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;
+;
+
+programmer
+  id    = "xplainedpro";
+  desc  = "Atmel AVR XplainedPro in JTAG mode";
+  type  = "jtagice3";
+  connection_type = usb;
+  usbpid = 0x2111;
 ;
 
 
diff --git a/configure.ac b/configure.ac
index 2dc712c4..bb82f3f5 100644
--- a/configure.ac
+++ b/configure.ac
@@ -23,7 +23,7 @@
 # Process this file with autoconf to produce a configure script.
 
 AC_PREREQ(2.60)
-AC_INIT(avrdude, 6.1-svn-20131205, avrdude-dev@nongnu.org)
+AC_INIT(avrdude, 6.1-svn-20140226, avrdude-dev@nongnu.org)
 
 AC_CANONICAL_BUILD
 AC_CANONICAL_HOST
diff --git a/jtag3.c b/jtag3.c
index 0a1ef41a..f34f6e37 100644
--- a/jtag3.c
+++ b/jtag3.c
@@ -84,8 +84,13 @@ struct pdata
 #define PGM_FL_IS_DW		(0x0001)
 #define PGM_FL_IS_PDI           (0x0002)
 #define PGM_FL_IS_JTAG          (0x0004)
+#define PGM_FL_IS_EDBG          (0x0008)
 
 static int jtag3_open(PROGRAMMER * pgm, char * port);
+static int jtag3_edbg_prepare(PROGRAMMER * pgm);
+static int jtag3_edbg_signoff(PROGRAMMER * pgm);
+static int jtag3_edbg_send(PROGRAMMER * pgm, unsigned char * data, size_t len);
+static int jtag3_edbg_recv_frame(PROGRAMMER * pgm, unsigned char **msg);
 
 static int jtag3_initialize(PROGRAMMER * pgm, AVRPART * p);
 static int jtag3_chip_erase(PROGRAMMER * pgm, AVRPART * p);
@@ -399,6 +404,9 @@ int jtag3_send(PROGRAMMER * pgm, unsigned char * data, size_t len)
 {
   unsigned char *buf;
 
+  if (pgm->flag & PGM_FL_IS_EDBG)
+    return jtag3_edbg_send(pgm, data, len);
+
   if (verbose >= 3)
     fprintf(stderr, "\n%s: jtag3_send(): sending %lu bytes\n",
 	    progname, (unsigned long)len);
@@ -419,7 +427,7 @@ int jtag3_send(PROGRAMMER * pgm, unsigned char * data, size_t len)
     fprintf(stderr,
 	    "%s: jtag3_send(): failed to send command to serial port\n",
 	    progname);
-    exit(1);
+    return -1;
   }
 
   free(buf);
@@ -427,6 +435,193 @@ int jtag3_send(PROGRAMMER * pgm, unsigned char * data, size_t len)
   return 0;
 }
 
+static int jtag3_edbg_send(PROGRAMMER * pgm, unsigned char * data, size_t len)
+{
+  unsigned char buf[USBDEV_MAX_XFER_3];
+  unsigned char status[USBDEV_MAX_XFER_3];
+  int rv;
+
+  if (verbose >= 4)
+    {
+      memset(buf, 0, pgm->fd.usb.max_xfer);
+      memset(status, 0, pgm->fd.usb.max_xfer);
+    }
+
+  if (verbose >= 3)
+    fprintf(stderr, "\n%s: jtag3_edbg_send(): sending %lu bytes\n",
+	    progname, (unsigned long)len);
+
+  if (len + 8 > pgm->fd.usb.max_xfer)
+    {
+      fprintf(stderr,
+	      "%s: jtag3_edbg_send(): Fragmentation not (yet) implemented!\n",
+	      progname);
+      return -1;
+    }
+  buf[0] = EDBG_VENDOR_AVR_CMD;
+  buf[1] = (1 << 4) | 1;	/* first out of a total of 1 fragments */
+  buf[2] = (len + 4) >> 8;
+  buf[3] = (len + 4) & 0xff;
+  buf[4] = TOKEN;
+  buf[5] = 0;                   /* dummy */
+  u16_to_b2(buf + 6, PDATA(pgm)->command_sequence);
+  memcpy(buf + 8, data, len);
+
+  if (serial_send(&pgm->fd, buf, pgm->fd.usb.max_xfer) != 0) {
+    fprintf(stderr,
+	    "%s: jtag3_edbg_send(): failed to send command to serial port\n",
+	    progname);
+    return -1;
+  }
+  rv = serial_recv(&pgm->fd, status, pgm->fd.usb.max_xfer);
+
+  if (rv < 0) {
+    /* timeout in receive */
+    if (verbose > 1)
+      fprintf(stderr,
+	      "%s: jtag3_edbg_send(): Timeout receiving packet\n",
+	      progname);
+    return -1;
+  }
+  if (status[0] != EDBG_VENDOR_AVR_CMD || status[1] != 0x01)
+    {
+      /* what to do in this case? */
+      fprintf(stderr,
+	      "%s: jtag3_edbg_send(): Unexpected response 0x%02x, 0x%02x\n",
+	      progname, status[0], status[1]);
+    }
+
+  return 0;
+}
+
+/*
+ * Send out all the CMSIS-DAP stuff needed to prepare the ICE.
+ */
+static int jtag3_edbg_prepare(PROGRAMMER * pgm)
+{
+  unsigned char buf[USBDEV_MAX_XFER_3];
+  unsigned char status[USBDEV_MAX_XFER_3];
+  int rv;
+
+  if (verbose >= 3)
+    fprintf(stderr, "\n%s: jtag3_edbg_prepare()\n",
+	    progname);
+
+  if (verbose >= 4)
+    memset(buf, 0, USBDEV_MAX_XFER_3);
+
+  buf[0] = CMSISDAP_CMD_CONNECT;
+  buf[1] = CMSISDAP_CONN_SWD;
+  if (serial_send(&pgm->fd, buf, USBDEV_MAX_XFER_3) != 0) {
+    fprintf(stderr,
+	    "%s: jtag3_edbg_prepare(): failed to send command to serial port\n",
+	    progname);
+    return -1;
+  }
+  rv = serial_recv(&pgm->fd, status, USBDEV_MAX_XFER_3);
+  if (rv != USBDEV_MAX_XFER_3) {
+    fprintf(stderr,
+	    "%s: jtag3_edbg_prepare(): failed to read from serial port (%d)\n",
+	    progname, rv);
+    return -1;
+  }
+  if (status[0] != CMSISDAP_CMD_CONNECT ||
+      status[1] == 0)
+    fprintf(stderr,
+	    "%s: jtag3_edbg_prepare(): unexpected response 0x%02x, 0x%02x\n",
+	    progname, status[0], status[1]);
+  if (verbose >= 2)
+    fprintf(stderr,
+	    "%s: jtag3_edbg_prepare(): connection status 0x%02x\n",
+	    progname, status[1]);
+
+  buf[0] = CMSISDAP_CMD_LED;
+  buf[1] = CMSISDAP_LED_CONNECT;
+  buf[2] = 1;
+  if (serial_send(&pgm->fd, buf, USBDEV_MAX_XFER_3) != 0) {
+    fprintf(stderr,
+	    "%s: jtag3_edbg_prepare(): failed to send command to serial port\n",
+	    progname);
+    return -1;
+  }
+  rv = serial_recv(&pgm->fd, status, USBDEV_MAX_XFER_3);
+  if (rv != USBDEV_MAX_XFER_3) {
+    fprintf(stderr,
+	    "%s: jtag3_edbg_prepare(): failed to read from serial port (%d)\n",
+	    progname, rv);
+    return -1;
+  }
+  if (status[0] != CMSISDAP_CMD_LED ||
+      status[1] != 0)
+    fprintf(stderr,
+	    "%s: jtag3_edbg_prepare(): unexpected response 0x%02x, 0x%02x\n",
+	    progname, status[0], status[1]);
+
+  return 0;
+}
+
+
+/*
+ * Send out all the CMSIS-DAP stuff when signing off.
+ */
+static int jtag3_edbg_signoff(PROGRAMMER * pgm)
+{
+  unsigned char buf[USBDEV_MAX_XFER_3];
+  unsigned char status[USBDEV_MAX_XFER_3];
+  int rv;
+
+  if (verbose >= 3)
+    fprintf(stderr, "\n%s: jtag3_edbg_signoff()\n",
+	    progname);
+
+  if (verbose >= 4)
+    memset(buf, 0, USBDEV_MAX_XFER_3);
+
+  buf[0] = CMSISDAP_CMD_LED;
+  buf[1] = CMSISDAP_LED_CONNECT;
+  buf[2] = 0;
+  if (serial_send(&pgm->fd, buf, USBDEV_MAX_XFER_3) != 0) {
+    fprintf(stderr,
+	    "%s: jtag3_edbg_signoff(): failed to send command to serial port\n",
+	    progname);
+    return -1;
+  }
+  rv = serial_recv(&pgm->fd, status, USBDEV_MAX_XFER_3);
+  if (rv != USBDEV_MAX_XFER_3) {
+    fprintf(stderr,
+	    "%s: jtag3_edbg_signoff(): failed to read from serial port (%d)\n",
+	    progname, rv);
+    return -1;
+  }
+  if (status[0] != CMSISDAP_CMD_LED ||
+      status[1] != 0)
+    fprintf(stderr,
+	    "%s: jtag3_edbg_signoff(): unexpected response 0x%02x, 0x%02x\n",
+	    progname, status[0], status[1]);
+
+  buf[0] = CMSISDAP_CMD_DISCONNECT;
+  if (serial_send(&pgm->fd, buf, USBDEV_MAX_XFER_3) != 0) {
+    fprintf(stderr,
+	    "%s: jtag3_edbg_signoff(): failed to send command to serial port\n",
+	    progname);
+    return -1;
+  }
+  rv = serial_recv(&pgm->fd, status, USBDEV_MAX_XFER_3);
+  if (rv != USBDEV_MAX_XFER_3) {
+    fprintf(stderr,
+	    "%s: jtag3_edbg_signoff(): failed to read from serial port (%d)\n",
+	    progname, rv);
+    return -1;
+  }
+  if (status[0] != CMSISDAP_CMD_DISCONNECT ||
+      status[1] != 0)
+    fprintf(stderr,
+	    "%s: jtag3_edbg_signoff(): unexpected response 0x%02x, 0x%02x\n",
+	    progname, status[0], status[1]);
+
+  return 0;
+}
+
 
 static int jtag3_drain(PROGRAMMER * pgm, int display)
 {
@@ -446,6 +641,9 @@ static int jtag3_recv_frame(PROGRAMMER * pgm, unsigned char **msg) {
   int rv;
   unsigned char *buf = NULL;
 
+  if (pgm->flag & PGM_FL_IS_EDBG)
+    return jtag3_edbg_recv_frame(pgm, msg);
+
   if (verbose >= 4)
     fprintf(stderr, "%s: jtag3_recv():\n", progname);
 
@@ -454,6 +652,8 @@ static int jtag3_recv_frame(PROGRAMMER * pgm, unsigned char **msg) {
 	    progname);
     return -1;
   }
+  if (verbose >= 4)
+    memset(buf, 0, pgm->fd.usb.max_xfer);
 
   rv = serial_recv(&pgm->fd, buf, pgm->fd.usb.max_xfer);
 
@@ -472,6 +672,62 @@ static int jtag3_recv_frame(PROGRAMMER * pgm, unsigned char **msg) {
   return rv;
 }
 
+static int jtag3_edbg_recv_frame(PROGRAMMER * pgm, unsigned char **msg) {
+  int rv, len;
+  unsigned char *buf = NULL;
+
+  if (verbose >= 4)
+    fprintf(stderr, "%s: jtag3_edbg_recv():\n", progname);
+
+  if ((buf = malloc(pgm->fd.usb.max_xfer)) == NULL) {
+    fprintf(stderr, "%s: jtag3_edbg_recv(): out of memory\n",
+	    progname);
+    return -1;
+  }
+
+  buf[0] = EDBG_VENDOR_AVR_RSP;
+
+  if (serial_send(&pgm->fd, buf, pgm->fd.usb.max_xfer) != 0) {
+    fprintf(stderr,
+	    "%s: jtag3_edbg_recv(): error sending CMSIS-DAP vendor command\n",
+	    progname);
+    return -1;
+  }
+
+  rv = serial_recv(&pgm->fd, buf, pgm->fd.usb.max_xfer);
+
+  if (rv < 0) {
+    /* timeout in receive */
+    if (verbose > 1)
+      fprintf(stderr,
+	      "%s: jtag3_edbg_recv(): Timeout receiving packet\n",
+	      progname);
+    free(buf);
+    return -1;
+  }
+
+  if (buf[0] != EDBG_VENDOR_AVR_RSP ||
+      buf[1] != ((1 << 4) | 1)) {
+    fprintf(stderr,
+	    "%s: jtag3_edbg_recv(): Unexpected response 0x%02x, 0x%02x\n",
+	    progname, buf[0], buf[1]);
+    return -1;
+  }
+  /* calculate length from response; CMSIS-DAP response might be larger */
+  len = (buf[2] << 8) | buf[3];
+  if (len > rv + 4) {
+    fprintf(stderr,
+	    "%s: jtag3_edbg_recv(): Unexpected length value (%d > %d)\n",
+	    progname, len, rv + 4);
+    len = rv + 4;
+  }
+  memmove(buf, buf + 4, len);
+
+  *msg = buf;
+
+  return rv;
+}
+
 int jtag3_recv(PROGRAMMER * pgm, unsigned char **msg) {
   unsigned short r_seqno;
   int rv;
@@ -562,6 +818,11 @@ int jtag3_getsync(PROGRAMMER * pgm, int mode) {
   if (verbose >= 3)
     fprintf(stderr, "%s: jtag3_getsync()\n", progname);
 
+  if (pgm->flag & PGM_FL_IS_EDBG) {
+    if (jtag3_edbg_prepare(pgm) < 0)
+      return -1;
+  }
+
   /* Get the sign-on information. */
   buf[0] = SCOPE_GENERAL;
   buf[1] = CMD3_SIGN_ON;
@@ -1034,9 +1295,15 @@ static int jtag3_open(PROGRAMMER * pgm, char * port)
   if (strncmp(port, "usb", 3) == 0) {
 #if defined(HAVE_LIBUSB)
     serdev = &usb_serdev_frame;
-    pinfo.usbinfo.vid = USB_VENDOR_ATMEL;
+    if (pgm->usbvid)
+      pinfo.usbinfo.vid = pgm->usbvid;
+    else
+      pinfo.usbinfo.vid = USB_VENDOR_ATMEL;
     pinfo.usbinfo.flags = 0;
-    pinfo.usbinfo.pid = USB_DEVICE_JTAGICE3;
+    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;
@@ -1052,6 +1319,17 @@ static int jtag3_open(PROGRAMMER * pgm, char * port)
     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
    */
@@ -1078,9 +1356,15 @@ static int jtag3_open_dw(PROGRAMMER * pgm, char * port)
   if (strncmp(port, "usb", 3) == 0) {
 #if defined(HAVE_LIBUSB)
     serdev = &usb_serdev_frame;
-    pinfo.usbinfo.vid = USB_VENDOR_ATMEL;
+    if (pgm->usbvid)
+      pinfo.usbinfo.vid = pgm->usbvid;
+    else
+      pinfo.usbinfo.vid = USB_VENDOR_ATMEL;
     pinfo.usbinfo.flags = 0;
-    pinfo.usbinfo.pid = USB_DEVICE_JTAGICE3;
+    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;
@@ -1096,6 +1380,17 @@ static int jtag3_open_dw(PROGRAMMER * pgm, char * port)
     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
    */
@@ -1122,9 +1417,15 @@ static int jtag3_open_pdi(PROGRAMMER * pgm, char * port)
   if (strncmp(port, "usb", 3) == 0) {
 #if defined(HAVE_LIBUSB)
     serdev = &usb_serdev_frame;
-    pinfo.usbinfo.vid = USB_VENDOR_ATMEL;
+    if (pgm->usbvid)
+      pinfo.usbinfo.vid = pgm->usbvid;
+    else
+      pinfo.usbinfo.vid = USB_VENDOR_ATMEL;
     pinfo.usbinfo.flags = 0;
-    pinfo.usbinfo.pid = USB_DEVICE_JTAGICE3;
+    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;
@@ -1140,6 +1441,17 @@ static int jtag3_open_pdi(PROGRAMMER * pgm, char * port)
     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
    */
@@ -1172,6 +1484,9 @@ void jtag3_close(PROGRAMMER * pgm)
   if (jtag3_command(pgm, buf, 4, &resp, "sign-off") >= 0)
     free(resp);
 
+  if (pgm->flag & PGM_FL_IS_EDBG)
+    jtag3_edbg_signoff(pgm);
+
   serial_close(&pgm->fd);
   pgm->fd.ifd = -1;
 }
diff --git a/jtag3_private.h b/jtag3_private.h
index c226cfe0..8ee37505 100644
--- a/jtag3_private.h
+++ b/jtag3_private.h
@@ -222,6 +222,47 @@
 #define XMEGA_ERASE_EEPROM_PAGE 0x06
 #define XMEGA_ERASE_USERSIG     0x07
 
+/* EDBG vendor commands */
+#define EDBG_VENDOR_AVR_CMD     0x80
+#define EDBG_VENDOR_AVR_RSP     0x81
+#define EDBG_VENDOR_AVR_EVT     0x82
+
+/* CMSIS-DAP commands */
+#define CMSISDAP_CMD_INFO       0x00 /* get info, followed by INFO byte */
+#  define CMSISDAP_INFO_VID         0x01 /* vendor ID (string) */
+#  define CMSISDAP_INFO_PID         0x02 /* product ID (string) */
+#  define CMSISDAP_INFO_SERIAL      0x03 /* serial number (string) */
+#  define CMSISDAP_INFO_FIRMWARE    0x04 /* firmware version (string) */
+#  define CMSISDAP_INFO_TARGET_VENDOR 0x05 /* target device vendor (string) */
+#  define CMSISDAP_INFO_TARGET_NAME   0x06 /* target device name (string) */
+#  define CMSISDAP_INFO_CAPABILITIES  0xF0 /* debug unit capabilities (byte) */
+#  define CMSISDAP_INFO_PACKET_COUNT  0xFE /* packet count (byte) (which packets, anyway?) */
+#  define CMSISDAP_INFO_PACKET_SIZE   0xFF /* packet size (short) */
+
+#define CMSISDAP_CMD_LED        0x01 /* LED control, followed by LED number and on/off byte */
+#  define CMSISDAP_LED_CONNECT      0x00 /* connect LED */
+#  define CMSISDAP_LED_RUNNING      0x01 /* running LED */
+
+#define CMSISDAP_CMD_CONNECT    0x02 /* connect to target, followed by DAP mode */
+#  define CMSISDAP_CONN_DEFAULT     0x00
+#  define CMSISDAP_CONN_SWD         0x01 /* serial wire debug */
+#  define CMSISDAP_CONN_JTAG        0x02 /* JTAG mode */
+
+#define CMSISDAP_CMD_DISCONNECT 0x03 /* disconnect from target */
+
+#define CMSISDAP_XFR_CONFIGURE  0x04 /* configure transfers; idle cycles (byte);
+                                        wait retry (short); match retry (short) */
+
+#define CMSISDAP_CMD_WRITEAPBORT 0x08 /* write to CoreSight ABORT register of target */
+
+#define CMSISDAP_CMD_DELAY      0x09 /* delay for number of microseconds (short) */
+
+#define CMSISDAP_CMD_RESET      0x0A /* reset target */
+
+#define CMSISDAP_CMD_SWJ_CLOCK  0x11 /* SWD/JTAG clock, (word) */
+
+#define CMSISDAP_CMD_SWD_CONFIGURE 0x13 /* configure SWD protocol; (byte) */
+
 #if !defined(JTAG3_PRIVATE_EXPORTED)
 
 struct mega_device_desc {
diff --git a/serial.h b/serial.h
index 57266283..29f73bcf 100644
--- a/serial.h
+++ b/serial.h
@@ -41,6 +41,7 @@ union filedescriptor
     int wep;                    /* bulk write endpoint */
     int eep;                    /* event read endpoint */
     int max_xfer;               /* max transfer size */
+    int use_interrupt_xfer;     /* device uses interrupt transfers */
   } usb;
 };
 
@@ -52,6 +53,7 @@ union pinfo
     unsigned short vid;
     unsigned short pid;
     unsigned short flags;
+#define PINFO_FL_USEHID         0x0001
   } usbinfo;
 };
 
diff --git a/usb_libusb.c b/usb_libusb.c
index b8e412a0..4e37be0e 100644
--- a/usb_libusb.c
+++ b/usb_libusb.c
@@ -70,6 +70,7 @@ static int usbdev_open(char * port, union pinfo pinfo, union filedescriptor *fd)
   usb_dev_handle *udev;
   char *serno, *cp2;
   int i;
+  int iface;
   size_t x;
 
   /*
@@ -151,6 +152,21 @@ static int usbdev_open(char * port, union pinfo pinfo, union filedescriptor *fd)
 			      progname, usb_strerror());
 		      strcpy(product, "[unnamed product]");
 		    }
+		  /*
+		   * The CMSIS-DAP specification mandates the string
+		   * "CMSIS-DAP" must be present somewhere in the
+		   * product name string for a device compliant to
+		   * that protocol.  Use this for the decisision
+		   * whether we have to search for a HID interface
+		   * below.
+		   */
+		  if(strstr(product, "CMSIS-DAP") != NULL)
+		  {
+		      pinfo.usbinfo.flags |= PINFO_FL_USEHID;
+		      /* The JTAGICE3 running the CMSIS-DAP firmware doesn't
+		       * use a separate endpoint for event reception. */
+		      fd->usb.eep = 0;
+		  }
 
 		  if (verbose)
 		    fprintf(stderr,
@@ -186,66 +202,102 @@ static int usbdev_open(char * port, union pinfo pinfo, union filedescriptor *fd)
 		  if (usb_set_configuration(udev, dev->config[0].bConfigurationValue))
 		    {
 		      fprintf(stderr,
-			      "%s: usbdev_open(): error setting configuration %d: %s\n",
+			      "%s: usbdev_open(): WARNING: failed to set configuration %d: %s\n",
 			      progname, dev->config[0].bConfigurationValue,
 			      usb_strerror());
-		      goto trynext;
+		      /* let's hope it has already been configured */
+		      // goto trynext;
 		    }
 
-		  usb_interface = dev->config[0].interface[0].altsetting[0].bInterfaceNumber;
-		  if (usb_claim_interface(udev, usb_interface))
+		  for (iface = 0; iface < dev->config[0].bNumInterfaces; iface++)
+		    {
+		      usb_interface = dev->config[0].interface[iface].altsetting[0].bInterfaceNumber;
+#ifdef LIBUSB_HAS_GET_DRIVER_NP
+		      /*
+		       * Many Linux systems attach the usbhid driver
+		       * by default to any HID-class device.  On
+		       * those, the driver needs to be detached before
+		       * we can claim the interface.
+		       */
+		      (void)usb_detach_kernel_driver_np(udev, usb_interface);
+#endif
+		      if (usb_claim_interface(udev, usb_interface))
+			{
+			  fprintf(stderr,
+				  "%s: usbdev_open(): error claiming interface %d: %s\n",
+				  progname, usb_interface, usb_strerror());
+			}
+		      else
+			{
+			  if (pinfo.usbinfo.flags & PINFO_FL_USEHID)
+			    {
+			      /* only consider an interface that is of class HID */
+			      if (dev->config[0].interface[iface].altsetting[0].bInterfaceClass !=
+				  USB_CLASS_HID)
+				continue;
+			      fd->usb.use_interrupt_xfer = 1;
+			    }
+			  break;
+			}
+		    }
+		  if (iface == dev->config[0].bNumInterfaces)
 		    {
 		      fprintf(stderr,
-			      "%s: usbdev_open(): error claiming interface %d: %s\n",
-			      progname, usb_interface, usb_strerror());
+			      "%s: usbdev_open(): no usable interface found\n",
+			      progname);
 		      goto trynext;
 		    }
 
 		  fd->usb.handle = udev;
 		  if (fd->usb.rep == 0)
-		  {
-		    /* Try finding out what our read endpoint is. */
-		    for (i = 0; i < dev->config[0].interface[0].altsetting[0].bNumEndpoints; i++)
 		    {
-		      int possible_ep = dev->config[0].interface[0].altsetting[0].
-			endpoint[i].bEndpointAddress;
+		      /* Try finding out what our read endpoint is. */
+		      for (i = 0; i < dev->config[0].interface[iface].altsetting[0].bNumEndpoints; i++)
+			{
+			  int possible_ep = dev->config[0].interface[iface].altsetting[0].
+			  endpoint[i].bEndpointAddress;
 
-		      if ((possible_ep & USB_ENDPOINT_DIR_MASK) != 0)
-		      {
-			if (verbose > 1)
+			  if ((possible_ep & USB_ENDPOINT_DIR_MASK) != 0)
+			    {
+			      if (verbose > 1)
+				{
+				  fprintf(stderr,
+					  "%s: usbdev_open(): using read endpoint 0x%02x\n",
+					  progname, possible_ep);
+				}
+			      fd->usb.rep = possible_ep;
+			      break;
+			    }
+			}
+		      if (fd->usb.rep == 0)
 			{
 			  fprintf(stderr,
-				  "%s: usbdev_open(): using read endpoint 0x%02x\n",
-				  progname, possible_ep);
+				  "%s: usbdev_open(): cannot find a read endpoint, using 0x%02x\n",
+				  progname, USBDEV_BULK_EP_READ_MKII);
+			  fd->usb.rep = USBDEV_BULK_EP_READ_MKII;
 			}
-			fd->usb.rep = possible_ep;
-			break;
-		      }
 		    }
-		    if (fd->usb.rep == 0)
+		  for (i = 0; i < dev->config[0].interface[iface].altsetting[0].bNumEndpoints; i++)
 		    {
-		      fprintf(stderr,
-			      "%s: usbdev_open(): cannot find a read endpoint, using 0x%02x\n",
-			      progname, USBDEV_BULK_EP_READ_MKII);
-		      fd->usb.rep = USBDEV_BULK_EP_READ_MKII;
-		    }
-		  }
-		  for (i = 0; i < dev->config[0].interface[0].altsetting[0].bNumEndpoints; i++)
-		    {
-		      if ((dev->config[0].interface[0].altsetting[0].endpoint[i].bEndpointAddress == fd->usb.rep ||
-			   dev->config[0].interface[0].altsetting[0].endpoint[i].bEndpointAddress == fd->usb.wep) &&
-			  dev->config[0].interface[0].altsetting[0].endpoint[i].wMaxPacketSize < fd->usb.max_xfer)
+		      if ((dev->config[0].interface[iface].altsetting[0].endpoint[i].bEndpointAddress == fd->usb.rep ||
+			   dev->config[0].interface[iface].altsetting[0].endpoint[i].bEndpointAddress == fd->usb.wep) &&
+			  dev->config[0].interface[iface].altsetting[0].endpoint[i].wMaxPacketSize < fd->usb.max_xfer)
 			{
 			  if (verbose != 0)
 			    fprintf(stderr,
 				    "%s: max packet size expected %d, but found %d due to EP 0x%02x's wMaxPacketSize\n",
 				    progname,
 				    fd->usb.max_xfer,
-				    dev->config[0].interface[0].altsetting[0].endpoint[i].wMaxPacketSize,
-				    dev->config[0].interface[0].altsetting[0].endpoint[i].bEndpointAddress);
-			  fd->usb.max_xfer = dev->config[0].interface[0].altsetting[0].endpoint[i].wMaxPacketSize;
+				    dev->config[0].interface[iface].altsetting[0].endpoint[i].wMaxPacketSize,
+				    dev->config[0].interface[iface].altsetting[0].endpoint[i].bEndpointAddress);
+			  fd->usb.max_xfer = dev->config[0].interface[iface].altsetting[0].endpoint[i].wMaxPacketSize;
 			}
 		    }
+		  if (pinfo.usbinfo.flags & PINFO_FL_USEHID)
+		    {
+		      if (usb_control_msg(udev, 0x21, 0x0a /* SET_IDLE */, 0, 0, NULL, 0, 100) < 0)
+			fprintf(stderr, "%s: usbdev_open(): SET_IDLE failed\n", progname);
+		    }
 		  return 0;
 		  trynext:
 		  usb_close(udev);
@@ -299,7 +351,10 @@ static int usbdev_send(union filedescriptor *fd, unsigned char *bp, size_t mlen)
    */
   do {
     tx_size = (mlen < fd->usb.max_xfer)? mlen: fd->usb.max_xfer;
-    rv = usb_bulk_write(udev, fd->usb.wep, (char *)bp, tx_size, 10000);
+    if (fd->usb.use_interrupt_xfer)
+      rv = usb_interrupt_write(udev, fd->usb.wep, (char *)bp, tx_size, 10000);
+    else
+      rv = usb_bulk_write(udev, fd->usb.wep, (char *)bp, tx_size, 10000);
     if (rv != tx_size)
     {
         fprintf(stderr, "%s: usbdev_send(): wrote %d out of %d bytes, err = %s\n",
@@ -341,16 +396,20 @@ static int usbdev_send(union filedescriptor *fd, unsigned char *bp, size_t mlen)
  * empty and more data are requested.
  */
 static int
-usb_fill_buf(usb_dev_handle *udev, int maxsize, int ep)
+usb_fill_buf(usb_dev_handle *udev, int maxsize, int ep, int use_interrupt_xfer)
 {
   int rv;
 
-  rv = usb_bulk_read(udev, ep, usbbuf, maxsize, 10000);
+  if (use_interrupt_xfer)
+    rv = usb_interrupt_read(udev, ep, usbbuf, maxsize, 10000);
+  else
+    rv = usb_bulk_read(udev, ep, usbbuf, maxsize, 10000);
   if (rv < 0)
     {
       if (verbose > 1)
-	fprintf(stderr, "%s: usb_fill_buf(): usb_bulk_read() error %s\n",
-		progname, usb_strerror());
+	fprintf(stderr, "%s: usb_fill_buf(): usb_%s_read() error %s\n",
+		progname, (use_interrupt_xfer? "interrupt": "bulk"),
+		usb_strerror());
       return -1;
     }
 
@@ -370,7 +429,7 @@ static int usbdev_recv(union filedescriptor *fd, unsigned char *buf, size_t nbyt
     {
       if (buflen <= bufptr)
 	{
-	  if (usb_fill_buf(udev, fd->usb.max_xfer, fd->usb.rep) < 0)
+	  if (usb_fill_buf(udev, fd->usb.max_xfer, fd->usb.rep, fd->usb.use_interrupt_xfer) < 0)
 	    return -1;
 	}
       amnt = buflen - bufptr > nbytes? nbytes: buflen - bufptr;
@@ -441,13 +500,18 @@ static int usbdev_recv_frame(union filedescriptor *fd, unsigned char *buf, size_
   n = 0;
   do
     {
-      rv = usb_bulk_read(udev, fd->usb.rep, usbbuf,
-			 fd->usb.max_xfer, 10000);
+      if (fd->usb.use_interrupt_xfer)
+	rv = usb_interrupt_read(udev, fd->usb.rep, usbbuf,
+				fd->usb.max_xfer, 10000);
+      else
+	rv = usb_bulk_read(udev, fd->usb.rep, usbbuf,
+			   fd->usb.max_xfer, 10000);
       if (rv < 0)
 	{
 	  if (verbose > 1)
-	    fprintf(stderr, "%s: usbdev_recv_frame(): usb_bulk_read(): %s\n",
-		    progname, usb_strerror());
+	    fprintf(stderr, "%s: usbdev_recv_frame(): usb_%s_read(): %s\n",
+		    progname, (fd->usb.use_interrupt_xfer? "interrupt": "bulk"),
+		    usb_strerror());
 	  return -1;
 	}
 
@@ -495,7 +559,10 @@ static int usbdev_drain(union filedescriptor *fd, int display)
   int rv;
 
   do {
-    rv = usb_bulk_read(udev, fd->usb.rep, usbbuf, fd->usb.max_xfer, 100);
+    if (fd->usb.use_interrupt_xfer)
+      rv = usb_interrupt_read(udev, fd->usb.rep, usbbuf, fd->usb.max_xfer, 100);
+    else
+      rv = usb_bulk_read(udev, fd->usb.rep, usbbuf, fd->usb.max_xfer, 100);
     if (rv > 0 && verbose >= 4)
       fprintf(stderr, "%s: usbdev_drain(): flushed %d characters\n",
 	      progname, rv);
diff --git a/usbdevs.h b/usbdevs.h
index c546f500..5bf91fdb 100644
--- a/usbdevs.h
+++ b/usbdevs.h
@@ -31,6 +31,8 @@
 #define USB_DEVICE_STK600      0x2106
 #define USB_DEVICE_AVRDRAGON   0x2107
 #define USB_DEVICE_JTAGICE3    0x2110
+#define USB_DEVICE_XPLAINEDPRO 0x2111
+#define USB_DEVICE_JTAG3_EDBG  0x2140
 
 /* JTAGICEmkII, AVRISPmkII */
 #define USBDEV_BULK_EP_WRITE_MKII 0x02