diff --git a/ChangeLog b/ChangeLog
index 626062d7..334d134b 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,19 @@
+2012-11-28  Joerg Wunsch <j.gnu@uriah.heep.sax.de>
+
+	First support for Atmel JTAGICE3.  Guessed from USB sniffer
+	traces made by Knut Schwichtenberg, and by similarity to
+	JTAGICEmkII.
+	Still quite incomplete, just megaAVR/JTAG is done by now.
+	* jtag3.c: New file.
+	* jtag3.h: (Dito.)
+	* jtag3_private.h: (Dito.)
+	* pgm_type.c: Add new programmers
+	* avrdude.conf.in: (Dito.)
+	* usbdevs.h: Add new parameters
+	* Makefile.am: Add new files
+	* usb_libusb.c: Handle separate event endpoint, and larger
+	(USB 2.0) packet sizes
+
 2012-11-26  Joerg Wunsch <j.gnu@uriah.heep.sax.de>
 
 	* jtagmkII.c: Change all the USB details (endpoint numbers,
diff --git a/Makefile.am b/Makefile.am
index f4befec9..0c06de0e 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -120,6 +120,9 @@ libavrdude_a_SOURCES = \
 	jtagmkII.c \
 	jtagmkII.h \
 	jtagmkII_private.h \
+	jtag3.c \
+	jtag3.h \
+	jtag3_private.h \
 	linux_ppdev.h \
 	lists.c \
 	lists.h \
diff --git a/NEWS b/NEWS
index 367ef53c..39bc1731 100644
--- a/NEWS
+++ b/NEWS
@@ -34,6 +34,8 @@ Current:
         X3(1), sck = DSR X3(2), mosi = DCD X3(3), reset = RI X3(4))
       + diecimila (alias for arduino-ft232r)
 
+    - Atmel JTAGICE3 (megaAVR/JTAG only so far)
+
   * Bugfixes
       - bug #34027: avrdude AT90S1200 Problem
       - bug #34518: loading intel hex files > 64k using record-type 4
diff --git a/avrdude.conf.in b/avrdude.conf.in
index 4aee6bfa..ffd72fc7 100644
--- a/avrdude.conf.in
+++ b/avrdude.conf.in
@@ -891,6 +891,28 @@ programmer
   connection_type = usb;
 ;
 
+programmer
+  id    = "jtag3";
+  desc  = "Atmel AVR JTAGICE3 in JTAG mode";
+  type  = "jtagice3";
+  connection_type = usb;
+;
+
+programmer
+  id    = "jtag3pdi";
+  desc  = "Atmel AVR JTAGICE3 in PDI mode";
+  type  = "jtagice3_pdi";
+  connection_type = usb;
+;
+
+programmer
+  id    = "jtag3dw";
+  desc  = "Atmel AVR JTAGICE3 in debugWIRE mode";
+  type  = "jtagice3_dw";
+  connection_type = usb;
+;
+
+
 programmer
   id    = "pavr";
   desc  = "Jason Kyle's pAVR Serial Programmer";
diff --git a/jtag3.c b/jtag3.c
new file mode 100644
index 00000000..afad7af6
--- /dev/null
+++ b/jtag3.c
@@ -0,0 +1,1982 @@
+/*
+ * avrdude - A Downloader/Uploader for AVR device programmers
+ * Copyright (C) 2012 Joerg Wunsch <j@uriah.heep.sax.de>
+ *
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+
+/* $Id$ */
+
+/*
+ * avrdude interface for Atmel JTAGICE3 programmer
+ */
+
+#include "ac_cfg.h"
+
+#include <ctype.h>
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+#include <sys/time.h>
+#include <time.h>
+
+#include "avrdude.h"
+#include "avr.h"
+#include "crc16.h"
+#include "pgm.h"
+#include "jtag3.h"
+#include "jtag3_private.h"
+#include "serial.h"
+#include "usbdevs.h"
+
+/*
+ * Private data for this programmer.
+ */
+struct pdata
+{
+  unsigned short command_sequence; /* Next cmd seqno to issue. */
+
+  /*
+   * See jtag3_read_byte() for an explanation of the flash and
+   * EEPROM page caches.
+   */
+  unsigned char *flash_pagecache;
+  unsigned long flash_pageaddr;
+  unsigned int flash_pagesize;
+
+  unsigned char *eeprom_pagecache;
+  unsigned long eeprom_pageaddr;
+  unsigned int eeprom_pagesize;
+
+  int prog_enabled;	     /* Cached value of PROGRAMMING status. */
+
+  /* JTAG chain stuff */
+  unsigned char jtagchain[4];
+
+  /* Start address of Xmega boot area */
+  unsigned long boot_start;
+};
+
+#define PDATA(pgm) ((struct pdata *)(pgm->cookie))
+
+/*
+ * The OCDEN fuse is bit 7 of the high fuse (hfuse).  In order to
+ * perform memory operations on MTYPE_SPM and MTYPE_EEPROM, OCDEN
+ * needs to be programmed.
+ *
+ * OCDEN should probably rather be defined via the configuration, but
+ * if this ever changes to a different fuse byte for one MCU, quite
+ * some code here needs to be generalized anyway.
+ */
+#define OCDEN (1 << 7)
+
+/*
+ * pgm->flag is marked as "for private use of the programmer".
+ * The following defines this programmer's use of that field.
+ */
+#define PGM_FL_IS_DW		(0x0001)
+#define PGM_FL_IS_PDI           (0x0002)
+#define PGM_FL_IS_JTAG          (0x0004)
+
+static int jtag3_open(PROGRAMMER * pgm, char * port);
+
+static int jtag3_command(PROGRAMMER *pgm, unsigned char *cmd, unsigned int cmdlen,
+			 unsigned char **resp, const char *descr);
+
+static int jtag3_initialize(PROGRAMMER * pgm, AVRPART * p);
+static int jtag3_chip_erase(PROGRAMMER * pgm, AVRPART * p);
+static int jtag3_read_byte(PROGRAMMER * pgm, AVRPART * p, AVRMEM * mem,
+                                unsigned long addr, unsigned char * value);
+static int jtag3_write_byte(PROGRAMMER * pgm, AVRPART * p, AVRMEM * mem,
+                                unsigned long addr, unsigned char data);
+static int jtag3_reset(PROGRAMMER * pgm, unsigned char flags);
+static int jtag3_set_sck_period(PROGRAMMER * pgm, double v);
+static int jtag3_setparm(PROGRAMMER * pgm, unsigned char scope,
+			 unsigned char section, unsigned char parm,
+			 unsigned char *value, unsigned char length);
+static void jtag3_print_parms1(PROGRAMMER * pgm, const char * p);
+static int jtag3_paged_write(PROGRAMMER * pgm, AVRPART * p, AVRMEM * m,
+                                unsigned int page_size,
+                                unsigned int addr, unsigned int n_bytes);
+static unsigned char jtag3_memtype(PROGRAMMER * pgm, AVRPART * p, unsigned long addr);
+static unsigned int jtag3_memaddr(PROGRAMMER * pgm, AVRPART * p, AVRMEM * m, unsigned long addr);
+
+
+void jtag3_setup(PROGRAMMER * pgm)
+{
+  if ((pgm->cookie = malloc(sizeof(struct pdata))) == 0) {
+    fprintf(stderr,
+	    "%s: jtag3_setup(): Out of memory allocating private data\n",
+	    progname);
+    exit(1);
+  }
+  memset(pgm->cookie, 0, sizeof(struct pdata));
+}
+
+void jtag3_teardown(PROGRAMMER * pgm)
+{
+  free(pgm->cookie);
+}
+
+
+static unsigned long
+b4_to_u32(unsigned char *b)
+{
+  unsigned long l;
+  l = b[0];
+  l += (unsigned)b[1] << 8;
+  l += (unsigned)b[2] << 16;
+  l += (unsigned)b[3] << 24;
+
+  return l;
+}
+static unsigned long
+b4_to_u32r(unsigned char *b)
+{
+  unsigned long l;
+  l = b[3];
+  l += (unsigned)b[2] << 8;
+  l += (unsigned)b[1] << 16;
+  l += (unsigned)b[0] << 24;
+
+  return l;
+}
+
+static void
+u32_to_b4(unsigned char *b, unsigned long l)
+{
+  b[0] = l & 0xff;
+  b[1] = (l >> 8) & 0xff;
+  b[2] = (l >> 16) & 0xff;
+  b[3] = (l >> 24) & 0xff;
+}
+static void
+u32_to_b4r(unsigned char *b, unsigned long l)
+{
+  b[3] = l & 0xff;
+  b[2] = (l >> 8) & 0xff;
+  b[1] = (l >> 16) & 0xff;
+  b[0] = (l >> 24) & 0xff;
+}
+
+static unsigned short
+b2_to_u16(unsigned char *b)
+{
+  unsigned short l;
+  l = b[0];
+  l += (unsigned)b[1] << 8;
+
+  return l;
+}
+
+static void
+u16_to_b2(unsigned char *b, unsigned short l)
+{
+  b[0] = l & 0xff;
+  b[1] = (l >> 8) & 0xff;
+}
+
+static void jtag3_print_data(unsigned char *b, size_t s)
+{
+  int i;
+
+  if (s < 2)
+    return;
+
+  for (i = 0; i < s; i++) {
+    fprintf(stderr, "0x%02x", b[i]);
+    if (i % 16 == 15)
+      putc('\n', stderr);
+    else
+      putc(' ', stderr);
+  }
+  if (i % 16 != 0)
+    putc('\n', stderr);
+}
+
+static void jtag3_prmsg(PROGRAMMER * pgm, unsigned char * data, size_t len)
+{
+  int i;
+
+  if (verbose >= 4) {
+    fprintf(stderr, "Raw message:\n");
+
+    for (i = 0; i < len; i++) {
+      fprintf(stderr, "%02x ", data[i]);
+      if (i % 16 == 15)
+	putc('\n', stderr);
+      else
+	putchar(' ');
+    }
+    if (i % 16 != 0)
+      putc('\n', stderr);
+  }
+
+  switch (data[0]) {
+    case SCOPE_INFO:
+      fprintf(stderr, "[info] ");
+      break;
+
+    case SCOPE_GENERAL:
+      fprintf(stderr, "[general] ");
+      break;
+
+    case SCOPE_AVR_ISP:
+      fprintf(stderr, "[AVRISP] ");
+      jtag3_print_data(data + 1, len - 1);
+      return;
+
+    case SCOPE_AVR:
+      fprintf(stderr, "[AVR] ");
+      break;
+
+    default:
+      fprintf(stderr, "[scope 0x%02x] ", data[0]);
+      break;
+  }
+
+  switch (data[1]) {
+    case RSP3_OK:
+      fprintf(stderr, "OK\n");
+      break;
+
+    case RSP3_FAILED:
+      fprintf(stderr, "FAILED");
+      if (len > 3)
+      {
+	char reason[50];
+	sprintf(reason, "0x%02x", data[3]);
+	switch (data[3])
+	{
+	  case RSP3_FAIL_NO_ANSWER:
+	    strcpy(reason, "target does not answer");
+	    break;
+
+	  case RSP3_FAIL_NO_TARGET_POWER:
+	    strcpy(reason, "no target power");
+	    break;
+
+	  case RSP3_FAIL_NOT_UNDERSTOOD:
+	    strcpy(reason, "command not understood");
+	    break;
+
+	  case RSP3_FAIL_WRONG_MODE:
+	    strcpy(reason, "wrong (programming) mode");
+	    break;
+	}
+	fprintf(stderr, ", reason: %s\n", reason);
+      }
+      else
+      {
+	fprintf(stderr, ", unspecified reason\n");
+      }
+      break;
+
+    case RSP3_DATA:
+      fprintf(stderr, "Data returned:\n");
+      jtag3_print_data(data + 2, len - 2);
+      break;
+
+    case RSP3_INFO:
+      fprintf(stderr, "Info returned:\n");
+      for (i = 2; i < len; i++) {
+	if (isprint(data[i]))
+	  putc(data[i], stderr);
+	else
+	  fprintf(stderr, "\\%03o", data[i]);
+      }
+      putc('\n', stderr);
+      break;
+
+    case RSP3_PC:
+      if (len < 7)
+      {
+	fprintf(stderr, "PC reply too short\n");
+      }
+      else
+      {
+	unsigned long pc = (data[6] << 24) | (data[5] << 16)
+	  | (data[4] << 8) | data[3];
+	fprintf(stderr, "PC 0x%0lx\n", pc);
+      }
+      break;
+
+#if 0
+  case EVT_BREAK:
+    fprintf(stderr, "BREAK event");
+    if (len >= 6) {
+      fprintf(stderr, ", PC = 0x%lx, reason ", b4_to_u32(data + 1));
+      switch (data[5]) {
+      case 0x00:
+	fprintf(stderr, "unspecified");
+	break;
+      case 0x01:
+	fprintf(stderr, "program break");
+	break;
+      case 0x02:
+	fprintf(stderr, "data break PDSB");
+	break;
+      case 0x03:
+	fprintf(stderr, "data break PDMSB");
+	break;
+      default:
+	fprintf(stderr, "unknown: 0x%02x", data[5]);
+      }
+    }
+    putc('\n', stderr);
+    break;
+
+  putc('\n', stderr);
+#endif
+
+  default:
+    fprintf(stderr, "unknown message 0x%02x\n", data[1]);
+  }
+}
+
+
+int jtag3_send(PROGRAMMER * pgm, unsigned char * data, size_t len)
+{
+  unsigned char *buf;
+
+  if (verbose >= 3)
+    fprintf(stderr, "\n%s: jtag3_send(): sending %lu bytes\n",
+	    progname, (unsigned long)len);
+
+  if ((buf = malloc(len + 4)) == NULL)
+    {
+      fprintf(stderr, "%s: jtag3_send(): out of memory",
+	      progname);
+      return -1;
+    }
+
+  buf[0] = TOKEN;
+  buf[1] = 0;                   /* dummy */
+  u16_to_b2(buf + 2, PDATA(pgm)->command_sequence);
+  memcpy(buf + 4, data, len);
+
+  if (serial_send(&pgm->fd, buf, len + 4) != 0) {
+    fprintf(stderr,
+	    "%s: jtag3_send(): failed to send command to serial port\n",
+	    progname);
+    exit(1);
+  }
+
+  free(buf);
+
+  return 0;
+}
+
+
+static int jtag3_drain(PROGRAMMER * pgm, int display)
+{
+  return serial_drain(&pgm->fd, display);
+}
+
+
+/*
+ * Receive one frame, return it in *msg.  Received sequence number is
+ * returned in seqno.  Any valid frame will be returned, regardless
+ * whether it matches the expected sequence number, including event
+ * notification frames (seqno == 0xffff).
+ *
+ * Caller must eventually free the buffer.
+ */
+static int jtag3_recv_frame(PROGRAMMER * pgm, unsigned char **msg) {
+  int rv;
+  unsigned char *buf = NULL;
+
+  if (verbose >= 4)
+    fprintf(stderr, "%s: jtag3_recv():\n", progname);
+
+  if ((buf = malloc(pgm->fd.usb.max_xfer)) == NULL) {
+    fprintf(stderr, "%s: jtag3_recv(): out of memory\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_recv(): Timeout receiving packet\n",
+	      progname);
+    free(buf);
+    return -1;
+  }
+
+  *msg = buf;
+
+  return rv;
+}
+
+int jtag3_recv(PROGRAMMER * pgm, unsigned char **msg) {
+  unsigned short r_seqno;
+  int rv;
+
+  for (;;) {
+    if ((rv = jtag3_recv_frame(pgm, msg)) <= 0)
+      return rv;
+
+    r_seqno = ((*msg)[2] << 8) | (*msg)[1];
+    if (verbose >= 3)
+      fprintf(stderr, "%s: jtag3_recv(): "
+	      "Got message seqno %d (command_sequence == %d)\n",
+	      progname, r_seqno, PDATA(pgm)->command_sequence);
+    if (r_seqno == PDATA(pgm)->command_sequence) {
+      if (++(PDATA(pgm)->command_sequence) == 0xffff)
+	PDATA(pgm)->command_sequence = 0;
+      /*
+       * We move the payload to the beginning of the buffer, to make
+       * the job easier for the caller.  We have to return the
+       * original pointer though, as the caller must free() it.
+       */
+      memmove(*msg, *msg + 3, rv);
+      rv -= 3;
+
+      return rv;
+    }
+    if (r_seqno == 0xffff) {
+      if (verbose >= 3)
+	fprintf(stderr, "%s: jtag3_recv(): got asynchronous event\n",
+		progname);
+    } else {
+      if (verbose >= 2)
+	fprintf(stderr, "%s: jtag3_recv(): "
+		"got wrong sequence number, %u != %u\n",
+		progname, r_seqno, PDATA(pgm)->command_sequence);
+    }
+    free(*msg);
+  }
+}
+
+static int jtag3_command(PROGRAMMER *pgm, unsigned char *cmd, unsigned int cmdlen,
+			 unsigned char **resp, const char *descr)
+{
+  int status;
+  unsigned char c;
+
+  if (verbose >= 2)
+    fprintf(stderr, "%s: Sending %s command: ",
+	    progname, descr);
+  jtag3_send(pgm, cmd, cmdlen);
+
+  status = jtag3_recv(pgm, resp);
+  if (status <= 0) {
+    if (verbose >= 2)
+      putc('\n', stderr);
+    fprintf(stderr,
+	    "%s: %s command: timeout/error communicating with programmer (status %d)\n",
+	    progname, descr, status);
+  } else if (verbose >= 3) {
+    putc('\n', stderr);
+    jtag3_prmsg(pgm, *resp, status);
+  } else if (verbose == 2)
+    fprintf(stderr, "0x%02x (%d bytes msg)\n", (*resp)[1], status);
+
+  c = (*resp)[1];
+  if ((c & RSP3_STATUS_MASK) != RSP3_OK) {
+    fprintf(stderr,
+	    "%s: bad response to %s command: 0x%02x\n",
+	    progname, descr, c);
+    free(*resp);
+    resp = 0;
+    return -1;
+  }
+
+  return status;
+}
+
+
+int jtag3_getsync(PROGRAMMER * pgm, int mode) {
+
+  unsigned char buf[3], *resp;
+
+  if (verbose >= 3)
+    fprintf(stderr, "%s: jtag3_getsync()\n", progname);
+
+  /* Get the sign-on information. */
+  buf[0] = SCOPE_GENERAL;
+  buf[1] = CMD3_SIGN_ON;
+  buf[2] = 0;
+
+  if (jtag3_command(pgm, buf, 3, &resp, "sign-on") < 0)
+    return -1;
+
+  free(resp);
+
+  return 0;
+}
+
+/*
+ * issue the 'chip erase' command to the AVR device
+ */
+static int jtag3_chip_erase(PROGRAMMER * pgm, AVRPART * p)
+{
+  unsigned char buf[8], *resp;
+
+  buf[0] = SCOPE_AVR;
+  buf[1] = CMD3_ERASE_MEMORY;
+  buf[2] = 0;
+  buf[3] = XMEGA_ERASE_CHIP;
+  buf[4] = buf[5] = buf[6] = buf[7] = 0; /* page address */
+
+  if (jtag3_command(pgm, buf, 8, &resp, "chip erase") < 0)
+    return -1;
+
+  free(resp);
+  return 0;
+}
+
+/*
+ * There is no chip erase functionality in debugWire mode.
+ */
+static int jtag3_chip_erase_dw(PROGRAMMER * pgm, AVRPART * p)
+{
+
+  fprintf(stderr, "%s: Chip erase not supported in debugWire mode\n",
+	  progname);
+
+  return 0;
+}
+
+/*
+ * Reset the target.
+ */
+static int jtag3_reset(PROGRAMMER * pgm, unsigned char flags)
+{
+#if 0
+  int status;
+  unsigned char buf[2], *resp, c;
+
+  /*
+   * In debugWire mode, don't reset.  Do a forced stop, and tell the
+   * ICE to stop any timers, too.
+   */
+  if (pgm->flag & PGM_FL_IS_DW) {
+    unsigned char parm[] = { 0 };
+
+    (void)jtag3_setparm(pgm, PAR_TIMERS_RUNNING, parm);
+  }
+
+  buf[0] = (pgm->flag & PGM_FL_IS_DW)? CMND_FORCED_STOP: CMND_RESET;
+  buf[1] = (pgm->flag & PGM_FL_IS_DW)? 1: flags;
+  if (verbose >= 2)
+    fprintf(stderr, "%s: jtag3_reset(): Sending %s command: ",
+	    progname, (pgm->flag & PGM_FL_IS_DW)? "stop": "reset");
+  jtag3_send(pgm, buf, 2);
+
+  status = jtag3_recv(pgm, &resp);
+  if (status <= 0) {
+    if (verbose >= 2)
+      putc('\n', stderr);
+    fprintf(stderr,
+	    "%s: jtag3_reset(): "
+	    "timeout/error communicating with programmer (status %d)\n",
+	    progname, status);
+    return -1;
+  }
+  if (verbose >= 3) {
+    putc('\n', stderr);
+    jtag3_prmsg(pgm, resp, status);
+  } else if (verbose == 2)
+    fprintf(stderr, "0x%02x (%d bytes msg)\n", resp[1], status);
+  c = resp[1];
+  free(resp);
+  if (c != RSP_OK) {
+    fprintf(stderr,
+	    "%s: jtag3_reset(): "
+	    "bad response to reset command: %s\n",
+	    progname, jtag3_get_rc(c));
+    return -1;
+  }
+
+#endif
+  return 0;
+}
+
+static int jtag3_program_enable_dummy(PROGRAMMER * pgm, AVRPART * p)
+{
+  return 0;
+}
+
+static int jtag3_program_enable(PROGRAMMER * pgm)
+{
+  unsigned char buf[3], *resp;
+  int use_ext_reset;
+
+  if (PDATA(pgm)->prog_enabled)
+    return 0;
+
+  for (use_ext_reset = 0; use_ext_reset <= 1; use_ext_reset++) {
+    buf[0] = SCOPE_AVR;
+    buf[1] = CMD3_ENTER_PROGMODE;
+    buf[2] = 0;
+
+    if (jtag3_command(pgm, buf, 3, &resp, "enter progmode") >= 0) {
+      free(resp);
+      break;
+    }
+
+    /* XXX activate external reset here */
+    if (verbose > 0)
+      fprintf(stderr,
+	      "%s: retrying with external reset applied\n",
+	      progname);
+  }
+
+  PDATA(pgm)->prog_enabled = 1;
+
+  return 0;
+}
+
+static int jtag3_program_disable(PROGRAMMER * pgm)
+{
+  unsigned char buf[3], *resp;
+
+  if (!PDATA(pgm)->prog_enabled)
+    return 0;
+
+  buf[0] = SCOPE_AVR;
+  buf[1] = CMD3_LEAVE_PROGMODE;
+  buf[2] = 0;
+
+  if (jtag3_command(pgm, buf, 3, &resp, "enter progmode") < 0)
+    return -1;
+
+  free(resp);
+
+  PDATA(pgm)->prog_enabled = 0;
+  //(void)jtag3_reset(pgm, 0x01);
+
+  return 0;
+}
+
+/*
+ * initialize the AVR device and prepare it to accept commands
+ */
+static int jtag3_initialize(PROGRAMMER * pgm, AVRPART * p)
+{
+  AVRMEM hfuse;
+  unsigned char conn = 0, parm[4];
+  const char *ifname;
+  unsigned char cmd[4], *resp, b;
+  int status;
+
+  if (pgm->flag & PGM_FL_IS_DW) {
+    ifname = "debugWire";
+    if (p->flags & AVRPART_HAS_DW)
+      conn = PARM3_CONN_DW;
+  } else if (pgm->flag & PGM_FL_IS_PDI) {
+    ifname = "PDI";
+    if (p->flags & AVRPART_HAS_PDI)
+      conn = PARM3_CONN_PDI;
+  } else {
+    ifname = "JTAG";
+    if (p->flags & AVRPART_HAS_JTAG)
+      conn = PARM3_CONN_JTAG;
+  }
+
+  if (conn == 0) {
+    fprintf(stderr, "%s: jtag3_initialize(): part %s has no %s interface\n",
+	    progname, p->desc, ifname);
+    return -1;
+  }
+
+  if (p->flags & AVRPART_HAS_PDI)
+    parm[0] = PARM3_ARCH_XMEGA;
+  else if (p->flags & AVRPART_HAS_DW)
+    parm[0] = PARM3_ARCH_TINY;
+  else
+    parm[0] = PARM3_ARCH_MEGA;
+  if (jtag3_setparm(pgm, SCOPE_AVR, 0, PARM3_ARCH, parm, 1) < 0)
+    return -1;
+
+  parm[0] = PARM3_SESS_PROGRAMMING;
+  if (jtag3_setparm(pgm, SCOPE_AVR, 0, PARM3_SESS_PURPOSE, parm, 1) < 0)
+    return -1;
+
+  parm[0] = conn;
+  if (jtag3_setparm(pgm, SCOPE_AVR, 1, PARM3_CONNECTION, parm, 1) < 0)
+    return -1;
+
+  if (conn == PARM3_CONN_JTAG && pgm->bitclock != 0.0)
+  {
+    unsigned int clock = 1E-3 / pgm->bitclock; /* kHz */
+    if (verbose >= 2)
+      fprintf(stderr, "%s: jtag3_initialize(): "
+	      "trying to set JTAG clock to %u kHz\n",
+	      progname, clock);
+    parm[0] = clock & 0xff;
+    parm[1] = (clock >> 8) & 0xff;
+    if (jtag3_setparm(pgm, SCOPE_AVR, 1,
+		      ((p->flags & AVRPART_HAS_PDI)? PARM3_CLK_XMEGA_JTAG: PARM3_CLK_MEGA_PROG),
+		      parm, 2) < 0)
+      return -1;
+  }
+  if (conn == PARM3_CONN_PDI && pgm->bitclock != 0.0)
+  {
+    unsigned int clock = 1E-3 / pgm->bitclock; /* kHz */
+    if (verbose >= 2)
+      fprintf(stderr, "%s: jtag3_initialize(): "
+	      "trying to set PDI clock to %u kHz\n",
+	      progname, clock);
+    parm[0] = clock & 0xff;
+    parm[1] = (clock >> 8) & 0xff;
+    if (jtag3_setparm(pgm, SCOPE_AVR, 1, PARM3_CLK_XMEGA_PDI, parm, 2) < 0)
+      return -1;
+  }
+  if (conn == PARM3_CONN_JTAG)
+  {
+    if (verbose >= 2)
+      fprintf(stderr, "%s: jtag3_initialize(): "
+	      "trying to set JTAG daisy-chain info to %d,%d,%d,%d\n",
+	      progname,
+	      PDATA(pgm)->jtagchain[0], PDATA(pgm)->jtagchain[1],
+	      PDATA(pgm)->jtagchain[2], PDATA(pgm)->jtagchain[3]);
+    if (jtag3_setparm(pgm, SCOPE_AVR, 1, PARM3_JTAGCHAIN, PDATA(pgm)->jtagchain, 4) < 0)
+      return -1;
+  }
+
+  /* set device descriptor data */
+  if ((p->flags & AVRPART_HAS_PDI))
+  {
+    struct xmega_device_desc xd;
+  }
+  else
+  {
+    struct mega_device_desc md;
+    LNODEID ln;
+    AVRMEM * m;
+
+    memset(&md, 0, sizeof md);
+
+    for (ln = lfirst(p->mem); ln; ln = lnext(ln)) {
+      m = ldata(ln);
+      if (strcmp(m->desc, "flash") == 0) {
+	PDATA(pgm)->flash_pagesize = m->page_size;
+	u16_to_b2(md.flash_page_size, m->page_size);
+	u32_to_b4(md.flash_size, m->size);
+	// do we need it?  just a wild guess
+	u32_to_b4(md.boot_address, (m->size - m->page_size * 4) / 2);
+      } else if (strcmp(m->desc, "eeprom") == 0) {
+	PDATA(pgm)->eeprom_pagesize = m->page_size;
+	md.eeprom_page_size = m->page_size;
+	u16_to_b2(md.eeprom_size, m->size);
+      }
+    }
+
+    //md.sram_offset[2] = p->sram;  // do we need it?
+    u16_to_b2(md.sram_offset, 0x200);
+    md.ocd_revision = 3;        /* XXX! */
+    md.always_one = 1;
+    md.allow_full_page_bitstream = (p->flags & AVRPART_ALLOWFULLPAGEBITSTREAM) != 0;
+    md.idr_address = p->idr;
+
+    if (p->eecr == 0)
+      p->eecr = 0x1f;		/* matches most "modern" mega/tiny AVRs */
+    md.eearh_address = p->eecr + 3;
+    md.eearl_address = p->eecr + 2;
+    md.eecr_address = p->eecr;
+    md.eedr_address = p->eecr + 1;
+    md.spmcr_address = p->spmcr;
+    //md.osccal_address = p->osccal;  // do we need it at all?
+    md.osccal_address = 0x46;	/* XXX */
+
+    if (jtag3_setparm(pgm, SCOPE_AVR, 2, PARM3_DEVICEDESC, (unsigned char *)&md, sizeof md) < 0)
+      return -1;
+  }
+
+  cmd[0] = SCOPE_AVR;
+  cmd[1] = CMD3_SIGN_ON;
+  cmd[2] = 0;
+  cmd[3] = 0;			/* external reset */
+
+  if ((status = jtag3_command(pgm, cmd, 4, &resp, "AVR sign-on")) < 0)
+    return -1;
+
+  /*
+   * Depending on the target connection, there are two different
+   * possible replies of the ICE.  For a JTAG connection, the reply
+   * format is RSP3_DATA, followed by 4 bytes of the JTAG ID read from
+   * the device (followed by a trailing 0).  For all other connections
+   * (except ISP which is handled completely differently, but that
+   * doesn't apply here anyway), the response is just RSP_OK.
+   */
+  if (resp[1] == RSP3_DATA && status >= 7 && verbose >= 1)
+    /* JTAG ID has been returned */
+    fprintf(stderr, "%s: JTAG ID returned: 0x%02x 0x%02x 0x%02x 0x%02x\n",
+	    progname, resp[3], resp[4], resp[5], resp[6]);
+
+  free(resp);
+
+  free(PDATA(pgm)->flash_pagecache);
+  free(PDATA(pgm)->eeprom_pagecache);
+  if ((PDATA(pgm)->flash_pagecache = malloc(PDATA(pgm)->flash_pagesize)) == NULL) {
+    fprintf(stderr, "%s: jtag3_initialize(): Out of memory\n",
+	    progname);
+    return -1;
+  }
+  if ((PDATA(pgm)->eeprom_pagecache = malloc(PDATA(pgm)->eeprom_pagesize)) == NULL) {
+    fprintf(stderr, "%s: jtag3_initialize(): Out of memory\n",
+	    progname);
+    free(PDATA(pgm)->flash_pagecache);
+    return -1;
+  }
+  PDATA(pgm)->flash_pageaddr = PDATA(pgm)->eeprom_pageaddr = (unsigned long)-1L;
+
+  if (jtag3_reset(pgm, 0x01) < 0)
+    return -1;
+
+  if ((pgm->flag & PGM_FL_IS_JTAG) && !(p->flags & AVRPART_HAS_PDI)) {
+    strcpy(hfuse.desc, "hfuse");
+    if (jtag3_read_byte(pgm, p, &hfuse, 1, &b) < 0)
+      return -1;
+    if ((b & OCDEN) != 0)
+      fprintf(stderr,
+	      "%s: jtag3_initialize(): warning: OCDEN fuse not programmed, "
+	      "single-byte EEPROM updates not possible\n",
+	      progname);
+  }
+
+  return 0;
+}
+
+static void jtag3_disable(PROGRAMMER * pgm)
+{
+
+  free(PDATA(pgm)->flash_pagecache);
+  PDATA(pgm)->flash_pagecache = NULL;
+  free(PDATA(pgm)->eeprom_pagecache);
+  PDATA(pgm)->eeprom_pagecache = NULL;
+
+  /*
+   * jtag3_program_disable() doesn't do anything if the
+   * device is currently not in programming mode, so just
+   * call it unconditionally here.
+   */
+  (void)jtag3_program_disable(pgm);
+}
+
+static void jtag3_enable(PROGRAMMER * pgm)
+{
+  return;
+}
+
+static int jtag3_parseextparms(PROGRAMMER * pgm, LISTID extparms)
+{
+  LNODEID ln;
+  const char *extended_param;
+  int rv = 0;
+
+  for (ln = lfirst(extparms); ln; ln = lnext(ln)) {
+    extended_param = ldata(ln);
+
+    if (strncmp(extended_param, "jtagchain=", strlen("jtagchain=")) == 0) {
+      unsigned int ub, ua, bb, ba;
+      if (sscanf(extended_param, "jtagchain=%u,%u,%u,%u", &ub, &ua, &bb, &ba)
+          != 4) {
+        fprintf(stderr,
+                "%s: jtag3_parseextparms(): invalid JTAG chain '%s'\n",
+                progname, extended_param);
+        rv = -1;
+        continue;
+      }
+      if (verbose >= 2) {
+        fprintf(stderr,
+                "%s: jtag3_parseextparms(): JTAG chain parsed as:\n"
+                "%s %u units before, %u units after, %u bits before, %u bits after\n",
+                progname,
+                progbuf, ub, ua, bb, ba);
+      }
+      PDATA(pgm)->jtagchain[0] = ub;
+      PDATA(pgm)->jtagchain[1] = ua;
+      PDATA(pgm)->jtagchain[2] = bb;
+      PDATA(pgm)->jtagchain[3] = ba;
+
+      continue;
+    }
+
+    fprintf(stderr,
+            "%s: jtag3_parseextparms(): invalid extended parameter '%s'\n",
+            progname, extended_param);
+    rv = -1;
+  }
+
+  return rv;
+}
+
+
+static int jtag3_open(PROGRAMMER * pgm, char * port)
+{
+  long baud;
+
+  if (verbose >= 2)
+    fprintf(stderr, "%s: 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;
+    baud = 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");
+    return -1;
+#endif
+  }
+
+  strcpy(pgm->port, port);
+  if (serial_open(port, baud, &pgm->fd)==-1) {
+    return -1;
+  }
+
+  /*
+   * drain any extraneous input
+   */
+  jtag3_drain(pgm, 0);
+
+  if (jtag3_getsync(pgm, PARM3_CONN_JTAG) < 0)
+    return -1;
+
+  return 0;
+}
+
+static int jtag3_open_dw(PROGRAMMER * pgm, char * port)
+{
+  long baud;
+
+  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;
+    baud = 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");
+    return -1;
+#endif
+  }
+
+  strcpy(pgm->port, port);
+  if (serial_open(port, baud, &pgm->fd)==-1) {
+    return -1;
+  }
+
+  /*
+   * drain any extraneous input
+   */
+  jtag3_drain(pgm, 0);
+
+  if (jtag3_getsync(pgm, PARM3_CONN_DW) < 0)
+    return -1;
+
+  return 0;
+}
+
+static int jtag3_open_pdi(PROGRAMMER * pgm, char * port)
+{
+  long baud;
+
+  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;
+    baud = 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");
+    return -1;
+#endif
+  }
+
+  strcpy(pgm->port, port);
+  if (serial_open(port, baud, &pgm->fd)==-1) {
+    return -1;
+  }
+
+  /*
+   * drain any extraneous input
+   */
+  jtag3_drain(pgm, 0);
+
+  if (jtag3_getsync(pgm, PARM3_CONN_PDI) < 0)
+    return -1;
+
+  return 0;
+}
+
+
+void jtag3_close(PROGRAMMER * pgm)
+{
+  unsigned char buf[4], *resp;
+
+  if (verbose >= 2)
+    fprintf(stderr, "%s: jtag3_close()\n", progname);
+
+#if 0
+  if (pgm->flag & PGM_FL_IS_PDI) {
+    /* When in PDI mode, restart target. */
+    buf[0] = CMND_GO;
+    if (verbose >= 2)
+      fprintf(stderr, "%s: jtag3_close(): Sending GO command: ",
+	      progname);
+    jtag3_send(pgm, buf, 1);
+
+    status = jtag3_recv(pgm, &resp);
+    if (status <= 0) {
+      if (verbose >= 2)
+	putc('\n', stderr);
+      fprintf(stderr,
+	      "%s: jtag3_close(): "
+	      "timeout/error communicating with programmer (status %d)\n",
+	      progname, status);
+    } else {
+      if (verbose >= 3) {
+	putc('\n', stderr);
+	jtag3_prmsg(pgm, resp, status);
+      } else if (verbose == 2)
+	fprintf(stderr, "0x%02x (%d bytes msg)\n", resp[1], status);
+      c = resp[1];
+      free(resp);
+      if (c != RSP_OK) {
+	fprintf(stderr,
+		"%s: jtag3_close(): "
+		"bad response to GO command: %s\n",
+		progname, jtag3_get_rc(c));
+      }
+    }
+  }
+#endif
+
+  buf[0] = SCOPE_AVR;
+  buf[1] = CMD3_SIGN_OFF;
+  buf[2] = buf[3] = 0;
+
+  if (jtag3_command(pgm, buf, 3, &resp, "AVR sign-off") >= 0)
+    free(resp);
+
+  buf[0] = SCOPE_GENERAL;
+  buf[1] = CMD3_SIGN_OFF;
+
+  if (jtag3_command(pgm, buf, 4, &resp, "sign-off") >= 0)
+    free(resp);
+
+  serial_close(&pgm->fd);
+  pgm->fd.ifd = -1;
+}
+
+static int jtag3_page_erase(PROGRAMMER * pgm, AVRPART * p, AVRMEM * m,
+                               unsigned int addr)
+{
+#if 0
+  unsigned char cmd[6];
+  unsigned char *resp;
+  int status, tries;
+  long otimeout = serial_recv_timeout;
+
+  if (verbose >= 2)
+    fprintf(stderr, "%s: jtag3_page_erase(.., %s, 0x%x)\n",
+	    progname, m->desc, addr);
+
+  if (!(p->flags & AVRPART_HAS_PDI)) {
+    fprintf(stderr, "%s: jtag3_page_erase: not an Xmega device\n",
+	    progname);
+    return -1;
+  }
+  if ((pgm->flag & PGM_FL_IS_DW)) {
+    fprintf(stderr, "%s: jtag3_page_erase: not applicable to debugWIRE\n",
+	    progname);
+    return -1;
+  }
+
+  if (jtag3_program_enable(pgm) < 0)
+    return -1;
+
+  cmd[0] = CMND_XMEGA_ERASE;
+  if (strcmp(m->desc, "flash") == 0) {
+    if (jtag3_memtype(pgm, p, addr) == MTYPE_FLASH)
+      cmd[1] = XMEGA_ERASE_APP_PAGE;
+    else
+      cmd[1] = XMEGA_ERASE_BOOT_PAGE;
+  } else if (strcmp(m->desc, "eeprom") == 0) {
+    cmd[1] = XMEGA_ERASE_EEPROM_PAGE;
+  } else if ( ( strcmp(m->desc, "usersig") == 0 ) ) {
+    cmd[1] = XMEGA_ERASE_USERSIG;
+  } else if ( ( strcmp(m->desc, "boot") == 0 ) ) {
+    cmd[1] = XMEGA_ERASE_BOOT_PAGE;
+  } else {
+    cmd[1] = XMEGA_ERASE_APP_PAGE;
+  }
+  serial_recv_timeout = 100;
+
+  /*
+   * Don't use jtag3_memaddr() here.  While with all other
+   * commands, firmware 7+ doesn't require the NVM offsets being
+   * applied, the erase page commands make an exception, and do
+   * require the NVM offsets as part of the (page) address.
+   */
+  u32_to_b4(cmd + 2, addr + m->offset);
+
+  tries = 0;
+
+  retry:
+  if (verbose >= 2)
+    fprintf(stderr, "%s: jtag3_page_erase(): "
+            "Sending xmega erase command: ",
+            progname);
+  jtag3_send(pgm, cmd, sizeof cmd);
+
+  status = jtag3_recv(pgm, &resp);
+  if (status <= 0) {
+    if (verbose >= 2)
+      putc('\n', stderr);
+    if (verbose >= 1)
+      fprintf(stderr,
+              "%s: jtag3_page_erase(): "
+              "timeout/error communicating with programmer (status %d)\n",
+              progname, status);
+    if (tries++ < 4) {
+      serial_recv_timeout *= 2;
+      goto retry;
+    }
+    fprintf(stderr,
+            "%s: jtag3_page_erase(): fatal timeout/"
+            "error communicating with programmer (status %d)\n",
+            progname, status);
+    serial_recv_timeout = otimeout;
+    return -1;
+  }
+  if (verbose >= 3) {
+    putc('\n', stderr);
+    jtag3_prmsg(pgm, resp, status);
+  } else if (verbose == 2)
+    fprintf(stderr, "0x%02x (%d bytes msg)\n", resp[1], status);
+  if (resp[1] != RSP_OK) {
+    fprintf(stderr,
+            "%s: jtag3_page_erase(): "
+            "bad response to xmega erase command: %s\n",
+            progname, jtag3_get_rc(resp[1]));
+    free(resp);
+    serial_recv_timeout = otimeout;
+    return -1;
+  }
+  free(resp);
+
+  serial_recv_timeout = otimeout;
+
+#endif
+  return 0;
+}
+
+static int jtag3_paged_write(PROGRAMMER * pgm, AVRPART * p, AVRMEM * m,
+                                unsigned int page_size,
+                                unsigned int addr, unsigned int n_bytes)
+{
+  unsigned int block_size;
+  unsigned int maxaddr = addr + n_bytes;
+  unsigned char *cmd;
+  unsigned char *resp;
+  int status, dynamic_memtype = 0;
+  long otimeout = serial_recv_timeout;
+
+  if (verbose >= 2)
+    fprintf(stderr, "%s: jtag3_paged_write(.., %s, %d, %d)\n",
+	    progname, m->desc, page_size, n_bytes);
+
+  if (!(pgm->flag & PGM_FL_IS_DW) && jtag3_program_enable(pgm) < 0)
+    return -1;
+
+  if (page_size == 0) page_size = 256;
+
+  if ((cmd = malloc(page_size + 13)) == NULL) {
+    fprintf(stderr, "%s: jtag3_paged_write(): Out of memory\n",
+	    progname);
+    return -1;
+  }
+
+  cmd[0] = SCOPE_AVR;
+  cmd[1] = CMD3_WRITE_MEMORY;
+  cmd[2] = 0;
+  if (strcmp(m->desc, "flash") == 0) {
+    PDATA(pgm)->flash_pageaddr = (unsigned long)-1L;
+    cmd[3] = jtag3_memtype(pgm, p, addr);
+    if (p->flags & AVRPART_HAS_PDI)
+      /* dynamically decide between flash/boot memtype */
+      dynamic_memtype = 1;
+  } else if (strcmp(m->desc, "eeprom") == 0) {
+    if (pgm->flag & PGM_FL_IS_DW) {
+      /*
+       * jtag3_paged_write() to EEPROM attempted while in
+       * DW mode.  Use jtag3_write_byte() instead.
+       */
+      for (; addr < maxaddr; addr++) {
+	status = jtag3_write_byte(pgm, p, m, addr, m->buf[addr]);
+	if (status < 0) {
+	  free(cmd);
+	  return -1;
+	}
+      }
+      free(cmd);
+      return n_bytes;
+    }
+    cmd[3] = ( p->flags & AVRPART_HAS_PDI ) ? MTYPE_EEPROM : MTYPE_EEPROM_PAGE;
+    PDATA(pgm)->eeprom_pageaddr = (unsigned long)-1L;
+  } else if ( ( strcmp(m->desc, "usersig") == 0 ) ) {
+    cmd[3] = MTYPE_USERSIG;
+  } else if ( ( strcmp(m->desc, "boot") == 0 ) ) {
+    cmd[3] = MTYPE_BOOT_FLASH;
+  } else if ( p->flags & AVRPART_HAS_PDI ) {
+    cmd[3] = MTYPE_FLASH;
+  } else {
+    cmd[3] = MTYPE_SPM;
+  }
+  serial_recv_timeout = 100;
+  for (; addr < maxaddr; addr += page_size) {
+    if ((maxaddr - addr) < page_size)
+      block_size = maxaddr - addr;
+    else
+      block_size = page_size;
+    if (verbose >= 3)
+      fprintf(stderr, "%s: jtag3_paged_write(): "
+	      "block_size at addr %d is %d\n",
+	      progname, addr, block_size);
+
+    if (dynamic_memtype)
+      cmd[3] = jtag3_memtype(pgm, p, addr);
+
+    u32_to_b4(cmd + 8, page_size);
+    u32_to_b4(cmd + 4, jtag3_memaddr(pgm, p, m, addr));
+    cmd[12] = 0;
+
+    /*
+     * The JTAG ICE will refuse to write anything but a full page, at
+     * least for the flash ROM.  If a partial page has been requested,
+     * set the remainder to 0xff.  (Maybe we should rather read back
+     * the existing contents instead before?  Doesn't matter much, as
+     * bits cannot be written to 1 anyway.)
+     */
+    memset(cmd + 13, 0xff, page_size);
+    memcpy(cmd + 13, m->buf + addr, block_size);
+
+    if ((status = jtag3_command(pgm, cmd, page_size + 13,
+				&resp, "write memory")) < 0) {
+      free(cmd);
+      serial_recv_timeout = otimeout;
+      return -1;
+    }
+
+    free(resp);
+  }
+
+  free(cmd);
+  serial_recv_timeout = otimeout;
+
+  return n_bytes;
+}
+
+static int jtag3_paged_load(PROGRAMMER * pgm, AVRPART * p, AVRMEM * m,
+                               unsigned int page_size,
+                               unsigned int addr, unsigned int n_bytes)
+{
+  unsigned int block_size;
+  unsigned int maxaddr = addr + n_bytes;
+  unsigned char cmd[12];
+  unsigned char *resp;
+  int status, dynamic_memtype = 0;
+  long otimeout = serial_recv_timeout;
+
+  if (verbose >= 2)
+    fprintf(stderr, "%s: jtag3_paged_load(.., %s, %d, %d)\n",
+	    progname, m->desc, page_size, n_bytes);
+
+  if (!(pgm->flag & PGM_FL_IS_DW) && jtag3_program_enable(pgm) < 0)
+    return -1;
+
+  page_size = m->readsize;
+
+  cmd[0] = SCOPE_AVR;
+  cmd[1] = CMD3_READ_MEMORY;
+  cmd[2] = 0;
+
+  if (strcmp(m->desc, "flash") == 0) {
+    cmd[3] = jtag3_memtype(pgm, p, addr);
+    if (p->flags & AVRPART_HAS_PDI)
+      /* dynamically decide between flash/boot memtype */
+      dynamic_memtype = 1;
+  } else if (strcmp(m->desc, "eeprom") == 0) {
+    cmd[3] = ( p->flags & AVRPART_HAS_PDI ) ? MTYPE_EEPROM : MTYPE_EEPROM_PAGE;
+    if (pgm->flag & PGM_FL_IS_DW)
+      return -1;
+  } else if ( ( strcmp(m->desc, "prodsig") == 0 ) ) {
+    cmd[3] = MTYPE_PRODSIG;
+  } else if ( ( strcmp(m->desc, "usersig") == 0 ) ) {
+    cmd[3] = MTYPE_USERSIG;
+  } else if ( ( strcmp(m->desc, "boot") == 0 ) ) {
+    cmd[3] = MTYPE_BOOT_FLASH;
+  } else if ( p->flags & AVRPART_HAS_PDI ) {
+    cmd[3] = MTYPE_FLASH;
+  } else {
+    cmd[3] = MTYPE_SPM;
+  }
+  serial_recv_timeout = 100;
+  for (; addr < maxaddr; addr += page_size) {
+    if ((maxaddr - addr) < page_size)
+      block_size = maxaddr - addr;
+    else
+      block_size = page_size;
+    if (verbose >= 3)
+      fprintf(stderr, "%s: jtag3_paged_load(): "
+	      "block_size at addr %d is %d\n",
+	      progname, addr, block_size);
+
+    if (dynamic_memtype)
+      cmd[3] = jtag3_memtype(pgm, p, addr);
+
+    u32_to_b4(cmd + 8, block_size);
+    u32_to_b4(cmd + 4, jtag3_memaddr(pgm, p, m, addr));
+
+    if ((status = jtag3_command(pgm, cmd, 12, &resp, "read memory")) < 0)
+      return -1;
+
+    if (resp[1] != RSP3_DATA ||
+	status < block_size + 4) {
+      fprintf(stderr, "%s: wrong/short reply to read memory command\n",
+	      progname);
+      serial_recv_timeout = otimeout;
+      free(resp);
+      return -1;
+    }
+    memcpy(m->buf + addr, resp + 3, status - 4);
+    free(resp);
+  }
+  serial_recv_timeout = otimeout;
+
+  return n_bytes;
+}
+
+static int jtag3_read_byte(PROGRAMMER * pgm, AVRPART * p, AVRMEM * mem,
+			      unsigned long addr, unsigned char * value)
+{
+  unsigned char cmd[12];
+  unsigned char *resp, *cache_ptr = NULL;
+  int status, unsupp = 0;
+  unsigned long paddr = 0UL, *paddr_ptr = NULL;
+  unsigned int pagesize = 0;
+
+  if (verbose >= 2)
+    fprintf(stderr, "%s: jtag3_read_byte(.., %s, 0x%lx, ...)\n",
+	    progname, mem->desc, addr);
+
+  if (!(pgm->flag & PGM_FL_IS_DW) && jtag3_program_enable(pgm) < 0)
+    return -1;
+
+  cmd[0] = SCOPE_AVR;
+  cmd[1] = CMD3_READ_MEMORY;
+  cmd[2] = 0;
+
+  addr += mem->offset;
+  cmd[3] = ( p->flags & AVRPART_HAS_PDI ) ? MTYPE_FLASH : MTYPE_FLASH_PAGE;
+  if (strcmp(mem->desc, "flash") == 0 ||
+      strcmp(mem->desc, "application") == 0 ||
+      strcmp(mem->desc, "apptable") == 0 ||
+      strcmp(mem->desc, "boot") == 0) {
+    pagesize = PDATA(pgm)->flash_pagesize;
+    paddr = addr & ~(pagesize - 1);
+    paddr_ptr = &PDATA(pgm)->flash_pageaddr;
+    cache_ptr = PDATA(pgm)->flash_pagecache;
+  } else if (strcmp(mem->desc, "eeprom") == 0) {
+    if ( (pgm->flag & PGM_FL_IS_DW) || ( p->flags & AVRPART_HAS_PDI ) ) {
+      /* debugWire cannot use page access for EEPROM */
+      cmd[3] = MTYPE_EEPROM;
+    } else {
+      cmd[3] = MTYPE_EEPROM_PAGE;
+      pagesize = mem->page_size;
+      paddr = addr & ~(pagesize - 1);
+      paddr_ptr = &PDATA(pgm)->eeprom_pageaddr;
+      cache_ptr = PDATA(pgm)->eeprom_pagecache;
+    }
+  } else if (strcmp(mem->desc, "lfuse") == 0) {
+    cmd[3] = MTYPE_FUSE_BITS;
+    addr = 0;
+    if (pgm->flag & PGM_FL_IS_DW)
+      unsupp = 1;
+  } else if (strcmp(mem->desc, "hfuse") == 0) {
+    cmd[3] = MTYPE_FUSE_BITS;
+    addr = 1;
+    if (pgm->flag & PGM_FL_IS_DW)
+      unsupp = 1;
+  } else if (strcmp(mem->desc, "efuse") == 0) {
+    cmd[3] = MTYPE_FUSE_BITS;
+    addr = 2;
+    if (pgm->flag & PGM_FL_IS_DW)
+      unsupp = 1;
+  } else if (strcmp(mem->desc, "lock") == 0) {
+    cmd[3] = MTYPE_LOCK_BITS;
+    if (pgm->flag & PGM_FL_IS_DW)
+      unsupp = 1;
+  } else if (strncmp(mem->desc, "fuse", strlen("fuse")) == 0) {
+    cmd[3] = MTYPE_FUSE_BITS;
+  } else if (strcmp(mem->desc, "usersig") == 0) {
+    cmd[3] = MTYPE_USERSIG;
+  } else if (strcmp(mem->desc, "prodsig") == 0) {
+    cmd[3] = MTYPE_PRODSIG;
+  } else if (strcmp(mem->desc, "calibration") == 0) {
+    cmd[3] = MTYPE_OSCCAL_BYTE;
+    if (pgm->flag & PGM_FL_IS_DW)
+      unsupp = 1;
+  } else if (strcmp(mem->desc, "signature") == 0) {
+    cmd[3] = MTYPE_SIGN_JTAG;
+
+    if (pgm->flag & PGM_FL_IS_DW) {
+#if 0
+      /*
+       * In debugWire mode, there is no accessible memory area to read
+       * the signature from, but the essential two bytes can be read
+       * as a parameter from the ICE.
+       */
+      unsigned char parm[4];
+
+      switch (addr) {
+      case 0:
+	*value = 0x1E;		/* Atmel vendor ID */
+	break;
+
+      case 1:
+      case 2:
+	if (jtag3_getparm(pgm, PAR_TARGET_SIGNATURE, parm) < 0)
+	  return -1;
+	*value = parm[2 - addr];
+	break;
+
+      default:
+	fprintf(stderr, "%s: illegal address %lu for signature memory\n",
+		progname, addr);
+	return -1;
+      }
+      return 0;
+#endif
+    }
+
+  }
+
+  /*
+   * If the respective memory area is not supported under debugWire,
+   * leave here.
+   */
+  if (unsupp) {
+    *value = 42;
+    return -1;
+  }
+
+  /*
+   * To improve the read speed, we used paged reads for flash and
+   * EEPROM, and cache the results in a page cache.
+   *
+   * Page cache validation is based on "{flash,eeprom}_pageaddr"
+   * (holding the base address of the most recent cache fill
+   * operation).  This variable is set to (unsigned long)-1L when the
+   * cache needs to be invalidated.
+   */
+  if (pagesize && paddr == *paddr_ptr) {
+    *value = cache_ptr[addr & (pagesize - 1)];
+    return 0;
+  }
+
+  if (pagesize) {
+    u32_to_b4(cmd + 8, pagesize);
+    u32_to_b4(cmd + 4, paddr);
+  } else {
+    u32_to_b4(cmd + 8, 1);
+    u32_to_b4(cmd + 4, addr);
+  }
+
+  if ((status = jtag3_command(pgm, cmd, 12, &resp, "read memory")) < 0)
+    return -1;
+
+  if (resp[1] != RSP3_DATA ||
+      status < (pagesize? pagesize: 1) + 4) {
+    fprintf(stderr, "%s: wrong/short reply to read memory command\n",
+	    progname);
+    free(resp);
+    return -1;
+  }
+
+  if (pagesize) {
+    *paddr_ptr = paddr;
+    memcpy(cache_ptr, resp + 3, pagesize);
+    *value = cache_ptr[addr & (pagesize - 1)];
+  } else
+    *value = resp[3];
+
+  free(resp);
+  return 0;
+}
+
+static int jtag3_write_byte(PROGRAMMER * pgm, AVRPART * p, AVRMEM * mem,
+			       unsigned long addr, unsigned char data)
+{
+  unsigned char cmd[14];
+  unsigned char *resp;
+  int status, need_progmode = 1, unsupp = 0;
+
+  if (verbose >= 2)
+    fprintf(stderr, "%s: jtag3_write_byte(.., %s, 0x%lx, ...)\n",
+	    progname, mem->desc, addr);
+
+  addr += mem->offset;
+
+  cmd[0] = SCOPE_AVR;
+  cmd[1] = CMD3_WRITE_MEMORY;
+  cmd[2] = 0;
+  cmd[3] = ( p->flags & AVRPART_HAS_PDI ) ? MTYPE_FLASH : MTYPE_SPM;
+  if (strcmp(mem->desc, "flash") == 0) {
+     need_progmode = 0;
+     PDATA(pgm)->flash_pageaddr = (unsigned long)-1L;
+     if (pgm->flag & PGM_FL_IS_DW)
+       unsupp = 1;
+  } else if (strcmp(mem->desc, "eeprom") == 0) {
+    cmd[3] = MTYPE_EEPROM;
+    need_progmode = 0;
+    PDATA(pgm)->eeprom_pageaddr = (unsigned long)-1L;
+  } else if (strcmp(mem->desc, "lfuse") == 0) {
+    cmd[3] = MTYPE_FUSE_BITS;
+    addr = 0;
+    if (pgm->flag & PGM_FL_IS_DW)
+      unsupp = 1;
+  } else if (strcmp(mem->desc, "hfuse") == 0) {
+    cmd[3] = MTYPE_FUSE_BITS;
+    addr = 1;
+    if (pgm->flag & PGM_FL_IS_DW)
+      unsupp = 1;
+  } else if (strcmp(mem->desc, "efuse") == 0) {
+    cmd[3] = MTYPE_FUSE_BITS;
+    addr = 2;
+    if (pgm->flag & PGM_FL_IS_DW)
+      unsupp = 1;
+  } else if (strncmp(mem->desc, "fuse", strlen("fuse")) == 0) {
+    cmd[3] = MTYPE_FUSE_BITS;
+  } else if (strcmp(mem->desc, "usersig") == 0) {
+    cmd[3] = MTYPE_USERSIG;
+  } else if (strcmp(mem->desc, "prodsig") == 0) {
+    cmd[3] = MTYPE_PRODSIG;
+  } else if (strcmp(mem->desc, "lock") == 0) {
+    cmd[3] = MTYPE_LOCK_BITS;
+    if (pgm->flag & PGM_FL_IS_DW)
+      unsupp = 1;
+  } else if (strcmp(mem->desc, "calibration") == 0) {
+    cmd[3] = MTYPE_OSCCAL_BYTE;
+    if (pgm->flag & PGM_FL_IS_DW)
+      unsupp = 1;
+  } else if (strcmp(mem->desc, "signature") == 0) {
+    cmd[3] = MTYPE_SIGN_JTAG;
+    if (pgm->flag & PGM_FL_IS_DW)
+      unsupp = 1;
+  }
+
+  if (unsupp)
+    return -1;
+
+  if (need_progmode) {
+    if (jtag3_program_enable(pgm) < 0)
+      return -1;
+  } else {
+    if (jtag3_program_disable(pgm) < 0)
+      return -1;
+  }
+
+  u32_to_b4(cmd + 8, 1);
+  u32_to_b4(cmd + 4, addr);
+  cmd[12] = 0;
+  cmd[13] = data;
+
+  if ((status = jtag3_command(pgm, cmd, 14, &resp, "write memory")) < 0)
+    return -1;
+
+  free(resp);
+
+  return 0;
+}
+
+
+/*
+ * Set the JTAG clock.  The actual frequency is quite a bit of
+ * guesswork, based on the values claimed by AVR Studio.  Inside the
+ * JTAG ICE, the value is the delay count of a delay loop between the
+ * JTAG clock edges.  A count of 0 bypasses the delay loop.
+ *
+ * As the STK500 expresses it as a period length (and we actualy do
+ * program a period length as well), we rather call it by that name.
+ */
+static int jtag3_set_sck_period(PROGRAMMER * pgm, double v)
+{
+#if 0
+  unsigned char dur;
+
+  v = 1 / v;			/* convert to frequency */
+  if (v >= 6.4e6)
+    dur = 0;
+  else if (v >= 2.8e6)
+    dur = 1;
+  else if (v >= 20.9e3)
+    dur = (unsigned char)(5.35e6 / v);
+  else
+    dur = 255;
+
+  return jtag3_setparm(pgm, PAR_OCD_JTAG_CLK, &dur);
+#endif
+  return 0;
+}
+
+
+/*
+ * Read (an) emulator parameter(s).
+ */
+int jtag3_getparm(PROGRAMMER * pgm, unsigned char scope,
+		  unsigned char section, unsigned char parm,
+		  unsigned char *value, unsigned char length)
+{
+  int status;
+  unsigned char buf[6], *resp, c;
+  char descr[60];
+
+  if (verbose >= 2)
+    fprintf(stderr, "%s: jtag3_getparm()\n", progname);
+
+  buf[0] = scope;
+  buf[1] = CMD3_GET_PARAMETER;
+  buf[2] = 0;
+  buf[3] = section;
+  buf[4] = parm;
+  buf[5] = length;
+
+  sprintf(descr, "get parameter (scope 0x%02x, section %d, parm %d)",
+	  scope, section, parm);
+
+  if ((status = jtag3_command(pgm, buf, 6, &resp, descr)) < 0)
+    return -1;
+
+  c = resp[1];
+  if (c != RSP3_DATA || status < 3) {
+    fprintf(stderr,
+	    "%s: jtag3_getparm(): "
+	    "bad response to %s\n",
+	    progname, descr);
+    free(resp);
+    return -1;
+  }
+
+  status -= 3;
+  memcpy(value, resp + 3, (length < status? length: status));
+  free(resp);
+
+  return 0;
+}
+
+/*
+ * Write an emulator parameter.
+ */
+static int jtag3_setparm(PROGRAMMER * pgm, unsigned char scope,
+			 unsigned char section, unsigned char parm,
+			 unsigned char *value, unsigned char length)
+{
+  int status;
+  unsigned char *buf, *resp;
+  char descr[60];
+
+  if (verbose >= 2)
+    fprintf(stderr, "%s: jtag3_setparm()\n", progname);
+
+  sprintf(descr, "set parameter (scope 0x%02x, section %d, parm %d)",
+	  scope, section, parm);
+
+  if ((buf = malloc(6 + length)) == NULL)
+  {
+    fprintf(stderr, "%s: jtag3_setparm(): Out of memory\n",
+	    progname);
+    return -1;
+  }
+
+  buf[0] = scope;
+  buf[1] = CMD3_SET_PARAMETER;
+  buf[2] = 0;
+  buf[3] = section;
+  buf[4] = parm;
+  buf[5] = length;
+  memcpy(buf + 6, value, length);
+
+  status = jtag3_command(pgm, buf, length + 6, &resp, descr);
+
+  free(buf);
+  free(resp);
+
+  return status;
+}
+
+
+static void jtag3_display(PROGRAMMER * pgm, const char * p)
+{
+  unsigned char parms[5];
+  unsigned char cmd[4], *resp, c;
+  int status;
+
+  /*
+   * Ask for:
+   *  PARM3_HW_VER (1 byte)
+   *  PARM3_FW_MAJOR (1 byte)
+   *  PARM3_FW_MINOR (1 byte)
+   *  PARM3_FW_RELEASE (2 bytes)
+   */
+  if (jtag3_getparm(pgm, SCOPE_GENERAL, 0, PARM3_HW_VER, parms, 5) < 0)
+    return;
+
+  cmd[0] = SCOPE_INFO;
+  cmd[1] = CMD3_GET_INFO;
+  cmd[2] = 0;
+  cmd[3] = CMD3_INFO_SERIAL;
+
+  if ((status = jtag3_command(pgm, cmd, 4, &resp, "get info (serial number)")) < 0)
+    return;
+
+  c = resp[1];
+  if (c != RSP3_INFO) {
+    fprintf(stderr,
+	    "%s: jtag3_display(): response is not RSP3_INFO\n",
+	    progname);
+    free(resp);
+    return;
+  }
+  memmove(resp, resp + 3, status - 3);
+  resp[status - 3] = 0;
+
+  fprintf(stderr, "%sICE hardware version: %d\n", p, parms[0]);
+  fprintf(stderr, "%sICE firmware version: %d.%02d (rel. %d)\n", p,
+	  parms[1], parms[2],
+	  (parms[3] | (parms[4] << 8)));
+  fprintf(stderr, "%sSerial number   : %s\n", p, resp);
+  free(resp);
+
+  jtag3_print_parms1(pgm, p);
+}
+
+
+static void jtag3_print_parms1(PROGRAMMER * pgm, const char * p)
+{
+  unsigned char buf[2];
+
+  if (jtag3_getparm(pgm, SCOPE_GENERAL, 1, PARM3_VTARGET, buf, 2) < 0)
+    return;
+
+  fprintf(stderr, "%sVtarget         : %.2f V\n", p,
+	  b2_to_u16(buf) / 1000.0);
+
+  if (jtag3_getparm(pgm, SCOPE_AVR, 1, PARM3_CLK_MEGA_PROG, buf, 2) < 0)
+    return;
+  fprintf(stderr, "%sJTAG clock megaAVR/program: %u kHz\n", p,
+	  b2_to_u16(buf));
+
+  if (jtag3_getparm(pgm, SCOPE_AVR, 1, PARM3_CLK_MEGA_DEBUG, buf, 2) < 0)
+    return;
+  fprintf(stderr, "%sJTAG clock megaAVR/debug:   %u kHz\n", p,
+	  b2_to_u16(buf));
+
+  if (jtag3_getparm(pgm, SCOPE_AVR, 1, PARM3_CLK_XMEGA_JTAG, buf, 2) < 0)
+    return;
+  fprintf(stderr, "%sJTAG clock Xmega: %u kHz\n", p,
+	  b2_to_u16(buf));
+
+  if (jtag3_getparm(pgm, SCOPE_AVR, 1, PARM3_CLK_XMEGA_PDI, buf, 2) < 0)
+    return;
+  fprintf(stderr, "%sPDI clock Xmega : %u kHz\n", p,
+	  b2_to_u16(buf));
+}
+
+static void jtag3_print_parms(PROGRAMMER * pgm)
+{
+  jtag3_print_parms1(pgm, "");
+}
+
+static unsigned char jtag3_memtype(PROGRAMMER * pgm, AVRPART * p, unsigned long addr)
+{
+  if ( p->flags & AVRPART_HAS_PDI ) {
+    if (addr >= PDATA(pgm)->boot_start)
+      return MTYPE_BOOT_FLASH;
+    else
+      return MTYPE_FLASH;
+  } else {
+    return MTYPE_FLASH_PAGE;
+  }
+}
+
+static unsigned int jtag3_memaddr(PROGRAMMER * pgm, AVRPART * p, AVRMEM * m, unsigned long addr)
+{
+#if 0
+  /*
+   * Xmega devices handled by V7+ firmware don't want to be told their
+   * m->offset within the write memory command.
+   */
+  if (PDATA(pgm)->fwver >= 0x700 && (p->flags & AVRPART_HAS_PDI) != 0) {
+    if (addr >= PDATA(pgm)->boot_start)
+      /*
+       * all memories but "flash" are smaller than boot_start anyway, so
+       * no need for an extra check we are operating on "flash"
+       */
+      return addr - PDATA(pgm)->boot_start;
+    else
+      /* normal flash, or anything else */
+      return addr;
+  }
+  /*
+   * Old firmware, or non-Xmega device.  Non-Xmega (and non-AVR32)
+   * devices always have an m->offset of 0, so we don't have to
+   * distinguish them here.
+   */
+#endif
+  return addr + m->offset;
+}
+
+
+const char jtag3_desc[] = "Atmel JTAGICE3";
+
+void jtag3_initpgm(PROGRAMMER * pgm)
+{
+  strcpy(pgm->type, "JTAGICE3");
+
+  /*
+   * mandatory functions
+   */
+  pgm->initialize     = jtag3_initialize;
+  pgm->display        = jtag3_display;
+  pgm->enable         = jtag3_enable;
+  pgm->disable        = jtag3_disable;
+  pgm->program_enable = jtag3_program_enable_dummy;
+  pgm->chip_erase     = jtag3_chip_erase;
+  pgm->open           = jtag3_open;
+  pgm->close          = jtag3_close;
+  pgm->read_byte      = jtag3_read_byte;
+  pgm->write_byte     = jtag3_write_byte;
+
+  /*
+   * optional functions
+   */
+  pgm->paged_write    = jtag3_paged_write;
+  pgm->paged_load     = jtag3_paged_load;
+  pgm->page_erase     = jtag3_page_erase;
+  pgm->print_parms    = jtag3_print_parms;
+  pgm->set_sck_period = jtag3_set_sck_period;
+  pgm->parseextparams = jtag3_parseextparms;
+  pgm->setup          = jtag3_setup;
+  pgm->teardown       = jtag3_teardown;
+  pgm->page_size      = 256;
+  pgm->flag           = PGM_FL_IS_JTAG;
+}
+
+const char jtag3_dw_desc[] = "Atmel JTAGICE3 in debugWire mode";
+
+void jtag3_dw_initpgm(PROGRAMMER * pgm)
+{
+  strcpy(pgm->type, "JTAGICE3_DW");
+
+  /*
+   * mandatory functions
+   */
+  pgm->initialize     = jtag3_initialize;
+  pgm->display        = jtag3_display;
+  pgm->enable         = jtag3_enable;
+  pgm->disable        = jtag3_disable;
+  pgm->program_enable = jtag3_program_enable_dummy;
+  pgm->chip_erase     = jtag3_chip_erase_dw;
+  pgm->open           = jtag3_open_dw;
+  pgm->close          = jtag3_close;
+  pgm->read_byte      = jtag3_read_byte;
+  pgm->write_byte     = jtag3_write_byte;
+
+  /*
+   * optional functions
+   */
+  pgm->paged_write    = jtag3_paged_write;
+  pgm->paged_load     = jtag3_paged_load;
+  pgm->print_parms    = jtag3_print_parms;
+  pgm->setup          = jtag3_setup;
+  pgm->teardown       = jtag3_teardown;
+  pgm->page_size      = 256;
+  pgm->flag           = PGM_FL_IS_DW;
+}
+
+const char jtag3_pdi_desc[] = "Atmel JTAGICE3 in PDI mode";
+
+void jtag3_pdi_initpgm(PROGRAMMER * pgm)
+{
+  strcpy(pgm->type, "JTAGICE3_PDI");
+
+  /*
+   * mandatory functions
+   */
+  pgm->initialize     = jtag3_initialize;
+  pgm->display        = jtag3_display;
+  pgm->enable         = jtag3_enable;
+  pgm->disable        = jtag3_disable;
+  pgm->program_enable = jtag3_program_enable_dummy;
+  pgm->chip_erase     = jtag3_chip_erase;
+  pgm->open           = jtag3_open_pdi;
+  pgm->close          = jtag3_close;
+  pgm->read_byte      = jtag3_read_byte;
+  pgm->write_byte     = jtag3_write_byte;
+
+  /*
+   * optional functions
+   */
+  pgm->paged_write    = jtag3_paged_write;
+  pgm->paged_load     = jtag3_paged_load;
+  pgm->page_erase     = jtag3_page_erase;
+  pgm->print_parms    = jtag3_print_parms;
+  pgm->setup          = jtag3_setup;
+  pgm->teardown       = jtag3_teardown;
+  pgm->page_size      = 256;
+  pgm->flag           = PGM_FL_IS_PDI;
+}
+
diff --git a/jtag3.h b/jtag3.h
new file mode 100644
index 00000000..107d5f32
--- /dev/null
+++ b/jtag3.h
@@ -0,0 +1,54 @@
+/*
+ * avrdude - A Downloader/Uploader for AVR device programmers
+ * Copyright (C) 2012 Joerg Wunsch <j@uriah.heep.sax.de>
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+
+/* $Id$ */
+
+#ifndef jtag3_h
+#define jtag3_h
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+int  jtag3_send(PROGRAMMER * pgm, unsigned char * data, size_t len);
+int  jtag3_recv(PROGRAMMER * pgm, unsigned char **msg);
+void jtag3_close(PROGRAMMER * pgm);
+int  jtag3_getsync(PROGRAMMER * pgm, int mode);
+int  jtag3_getparm(PROGRAMMER * pgm, unsigned char scope,
+		   unsigned char section, unsigned char parm,
+		   unsigned char *value, unsigned char length);
+extern const char jtag3_desc[];
+extern const char jtag3_dw_desc[];
+extern const char jtag3_pdi_desc[];
+void jtag3_initpgm (PROGRAMMER * pgm);
+void jtag3_dw_initpgm (PROGRAMMER * pgm);
+void jtag3_pdi_initpgm (PROGRAMMER * pgm);
+
+/*
+ * These functions are referenced from stk500v2.c for JTAGICE3 in
+ * one of the STK500v2 modi.
+ */
+void jtag3_setup(PROGRAMMER * pgm);
+void jtag3_teardown(PROGRAMMER * pgm);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
diff --git a/jtag3_private.h b/jtag3_private.h
new file mode 100644
index 00000000..156eaf90
--- /dev/null
+++ b/jtag3_private.h
@@ -0,0 +1,271 @@
+/*
+ * avrdude - A Downloader/Uploader for AVR device programmers
+ * Copyright (C) 2012 Joerg Wunsch <j@uriah.heep.sax.de>
+ *
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+
+/* $Id$ */
+
+
+/*
+ * JTAGICE3 definitions
+ * Reverse-engineered from various USB traces.
+ */
+
+#if !defined(JTAG3_PRIVATE_EXPORTED)
+/*
+ * Communication with the JTAGICE3 uses three data endpoints:
+ *
+ * Endpoint 0x01 (OUT) and 0x82 (IN) are the usual conversation
+ * endpoints, with a maximal packet size of 512 octets.  The
+ * JTAGICE3 does *not* work on older USB 1.1 hubs that would only
+ * allow for 64-octet max packet size.
+ *
+ * Endpoint 0x83 (IN) is also a bulk endpoint, with a max packetsize
+ * of 64 octets.  This endpoint is used by the ICE to deliver events
+ * from the ICE.
+ *
+ * The request (host -> ICE, EP 0x01) format is:
+ *
+ *  +---------------------------------------------
+ *  |   0   |  1  |  2 . 3 |  4  |  5  |  6  | ...
+ *  |       |     |        |     |     |     |
+ *  | token |dummy|serial# |scope| cmd |dummy| optional data
+ *  | 0x0e  |  0  |  NNNN  | SS  | CC  |  0  | ...
+ *  +---------------------------------------------
+ *
+ * Both dummy bytes are always 0.  The "scope" identifier appears
+ * to distinguish commands (responses, events, parameters) roughly:
+ *
+ * 0x01 - general scope ("hello", "goodbye", firmware info, target
+ *        voltage readout)
+ * 0x11 - scope for AVR in ISP mode (basically a wrapper around
+ *        the AVRISPmkII commands, as usual)
+ * 0x12 - scope for AVR (JTAG, PDI, debugWIRE)
+ *
+ * The serial number is counted up.
+ *
+ *
+ * The response (ICE -> host, EP 0x82) format is:
+ *
+ *  +--------------------------------------------------+
+ *  |   0   |  1 . 2 |  3  |  4  | ...           |  N  |
+ *  |       |        |     |     |               |     |
+ *  | token |serial# |scope| rsp | optional data |dummy|
+ *  | 0x0e  |  NNNN  | SS  | RR  | ...           |  0  |
+ *  +--------------------------------------------------+
+ *
+ * The response's serial number is mirrored from the request, but the
+ * dummy byte before the serial number is left out.  However, another
+ * zero dummy byte is always attached to the end of the response data.
+ * Response codes are similar to the JTAGICEmkII, 0x80 is a generic
+ * "OK" response, other responses above 0x80 indicate various data
+ * responses (parameter read, memory read, PC value), and 0xa0 is a
+ * generic "failure" response.  It appears the failure response gets
+ * another byte appended (probably indicating the reason) after the
+ * 0 dummy byte, but there's not enough analysis material so far.
+ *
+ *
+ * The event format (EP 0x83) is:
+ *
+ *  +----------------------------------------
+ *  |   0   |  1  |  2 . 3 |  4  |  5  | ...
+ *  |       |     |        |     |     |
+ *  | token |dummy|serial# |scope| evt | data
+ *  | 0x0e  |  0  |  NNNN  | SS  | EV  | ...
+ *  +----------------------------------------
+ */
+#define TOKEN 0x0e
+
+#endif /* JTAG3_PRIVATE_EXPORTED */
+
+#define SCOPE_INFO                 0x00
+#define SCOPE_GENERAL              0x01
+#define SCOPE_AVR_ISP              0x11
+#define SCOPE_AVR                  0x12
+
+/* Info scope */
+#define CMD3_GET_INFO              0x00
+
+/* byte after GET_INFO is always 0, next is: */
+#  define CMD3_INFO_NAME           0x80 /* JTAGICE3 */
+#  define CMD3_INFO_SERIAL         0x81 /* J3xxxxxxxxxx */
+
+/* Generic scope */
+#define CMD3_SET_PARAMETER         0x01
+#define CMD3_GET_PARAMETER         0x02
+#define CMD3_SIGN_ON               0x10
+#define CMD3_SIGN_OFF              0x11 /* takes one parameter? */
+
+/* AVR ISP scope: no commands of its own */
+
+/* AVR scope */
+//#define CMD3_SET_PARAMETER       0x01
+//#define CMD3_GET_PARAMETER       0x02
+//#define CMD3_SIGN_ON             0x10 /* an additional signon/-off pair */
+//#define CMD3_SIGN_OFF            0x11
+#define CMD3_ENTER_PROGMODE        0x15
+#define CMD3_LEAVE_PROGMODE        0x16
+#define CMD3_ERASE_MEMORY          0x20
+#define CMD3_READ_MEMORY           0x21
+#define CMD3_WRITE_MEMORY          0x23
+#define CMD3_READ_PC               0x35
+
+/* ICE responses */
+#define RSP3_OK                    0x80
+#define RSP3_INFO                  0x81
+#define RSP3_PC                    0x83
+#define RSP3_DATA                  0x84
+#define RSP3_FAILED                0xA0
+
+#define RSP3_STATUS_MASK           0xE0
+
+/* possible failure codes that could be appended to RSP3_FAILED: */
+#  define RSP3_FAIL_NO_ANSWER           0x20
+#  define RSP3_FAIL_NO_TARGET_POWER     0x22
+#  define RSP3_FAIL_WRONG_MODE          0x32 /* progmode vs. non-prog */
+#  define RSP3_FAIL_NOT_UNDERSTOOD      0x91
+
+/* ICE events */
+#define EVT3_BREAK                 0x40 /* AVR scope */
+#define EVT3_SLEEP                 0x11 /* General scope, also wakeup */
+#define EVT3_POWER                 0x10 /* General scope */
+
+/* memory types */
+#define MTYPE_SRAM        0x20	/* target's SRAM or [ext.] IO registers */
+#define MTYPE_EEPROM      0x22	/* EEPROM, what way? */
+#define MTYPE_SPM         0xA0	/* flash through LPM/SPM */
+#define MTYPE_FLASH_PAGE  0xB0	/* flash in programming mode */
+#define MTYPE_EEPROM_PAGE 0xB1	/* EEPROM in programming mode */
+#define MTYPE_FUSE_BITS   0xB2	/* fuse bits in programming mode */
+#define MTYPE_LOCK_BITS   0xB3	/* lock bits in programming mode */
+#define MTYPE_SIGN_JTAG   0xB4	/* signature in programming mode */
+#define MTYPE_OSCCAL_BYTE 0xB5	/* osccal cells in programming mode */
+#define MTYPE_FLASH       0xc0	/* xmega (app.) flash - undocumented in AVR067 */
+#define MTYPE_BOOT_FLASH  0xc1	/* xmega boot flash - undocumented in AVR067 */
+#define MTYPE_USERSIG     0xc5	/* xmega user signature - undocumented in AVR067 */
+#define MTYPE_PRODSIG     0xc6	/* xmega production signature - undocumented in AVR067 */
+
+/*
+ * Parameters are divided into sections, where the section number
+ * precedes each parameter address.  There are distinct parameter
+ * sets for generic and AVR scope.
+ */
+#define PARM3_HW_VER      0x00  /* section 0, generic scope, 1 byte */
+#define PARM3_FW_MAJOR    0x01  /* section 0, generic scope, 1 byte */
+#define PARM3_FW_MINOR    0x02  /* section 0, generic scope, 1 byte */
+#define PARM3_FW_RELEASE  0x03  /* section 0, generic scope, 1 byte;
+                                 * always asked for by Atmel Studio,
+                                 * but never displayed there */
+#define PARM3_VTARGET     0x00  /* section 1, generic scope, 2 bytes,
+                                 * in millivolts */
+#define PARM3_DEVICEDESC  0x00  /* section 2, memory etc. configuration,
+                                 * 31 bytes for tiny/mega AVR, 47 bytes
+                                 * for Xmega; is also used in command
+                                 * 0x36 in JTAGICEmkII, starting with
+                                 * firmware 7.x */
+
+#define PARM3_ARCH        0x00  /* section 0, AVR scope, 1 byte */
+#  define PARM3_ARCH_TINY   1   /* also small megaAVR with ISP/DW only */
+#  define PARM3_ARCH_MEGA   2
+#  define PARM3_ARCH_XMEGA  3
+
+#define PARM3_SESS_PURPOSE 0x01 /* section 0, AVR scope, 1 byte */
+#  define PARM3_SESS_PROGRAMMING 1
+#  define PARM3_SESS_DEBUGGING   2
+
+#define PARM3_CONNECTION  0x00  /* section 1, AVR scope, 1 byte */
+#  define PARM3_CONN_ISP    1
+#  define PARM3_CONN_JTAG   4
+#  define PARM3_CONN_DW     5
+#  define PARM3_CONN_PDI    6
+
+
+#define PARM3_JTAGCHAIN   0x01  /* JTAG chain info, AVR scope (units
+                                 * before/after, bits before/after), 4
+                                 * bytes */
+
+#define PARM3_CLK_MEGA_PROG  0x20 /* section 1, AVR scope, 2 bytes (kHz) */
+#define PARM3_CLK_MEGA_DEBUG 0x21 /* section 1, AVR scope, 2 bytes (kHz) */
+#define PARM3_CLK_XMEGA_JTAG 0x30 /* section 1, AVR scope, 2 bytes (kHz) */
+#define PARM3_CLK_XMEGA_PDI  0x31 /* section 1, AVR scope, 2 bytes (kHz) */
+
+
+
+/* Xmega erase memory types, for CMND_XMEGA_ERASE */
+#define XMEGA_ERASE_CHIP        0x00
+#define XMEGA_ERASE_APP         0x01
+#define XMEGA_ERASE_BOOT        0x02
+#define XMEGA_ERASE_EEPROM      0x03
+#define XMEGA_ERASE_APP_PAGE    0x04
+#define XMEGA_ERASE_BOOT_PAGE   0x05
+#define XMEGA_ERASE_EEPROM_PAGE 0x06
+#define XMEGA_ERASE_USERSIG     0x07
+
+#if !defined(JTAG3_PRIVATE_EXPORTED)
+
+struct mega_device_desc {
+    unsigned char flash_page_size[2];   // in bytes
+    unsigned char flash_size[4];        // in bytes
+    unsigned char dummy1[4];            // always 0
+    unsigned char boot_address[4];      // maximal (BOOTSZ = 3) bootloader
+                                        // address, in 16-bit words (!)
+    unsigned char sram_offset[2];       // pointing behind IO registers
+    unsigned char eeprom_size[2];
+    unsigned char eeprom_page_size;
+    unsigned char ocd_revision;         // see XML; basically:
+                                        // t13*, t2313*, t4313:        0
+                                        // all other DW devices:       1
+                                        // ATmega128(A):               1 (!)
+                                        // ATmega16*,162,169*,32*,64*: 2
+                                        // ATmega2560/2561:            4
+                                        // all other megaAVR devices:  3
+    unsigned char always_one;           // always = 1
+    unsigned char allow_full_page_bitstream; // old AVRs, see XML
+    unsigned char dummy2[2];            // always 0
+                                        // all IO addresses below are given
+                                        // in IO number space (without
+                                        // offset 0x20), even though e.g.
+                                        // OSCCAL always resides outside
+    unsigned char idr_address;          // IDR, aka. OCDR
+    unsigned char eearh_address;        // EEPROM access
+    unsigned char eearl_address;
+    unsigned char eecr_address;
+    unsigned char eedr_address;
+    unsigned char spmcr_address;
+    unsigned char osccal_address;
+};
+
+
+/* Xmega device descriptor */
+struct xmega_device_desc {
+    unsigned char nvm_app_offset[4];	// NVM offset for application flash
+    unsigned char nvm_boot_offset[4];	// NVM offset for boot flash
+    unsigned char nvm_eeprom_offset[4]; // NVM offset for EEPROM
+    unsigned char nvm_fuse_offset[4];	// NVM offset for fuses
+    unsigned char nvm_lock_offset[4];	// NVM offset for lock bits
+    unsigned char nvm_user_sig_offset[4]; // NVM offset for user signature row
+    unsigned char nvm_prod_sig_offset[4]; // NVM offset for production sign. row
+    unsigned char nvm_data_offset[4];	// NVM offset for data memory (SRAM + IO)
+    unsigned char app_size[4];		// size of application flash
+    unsigned char boot_size[2];		// size of boot flash
+    unsigned char flash_page_size[2];	// flash page size
+    unsigned char eeprom_size[2];	// size of EEPROM
+    unsigned char eeprom_page_size;	// EEPROM page size
+    unsigned char nvm_base_addr[2];	// IO space base address of NVM controller
+    unsigned char mcu_base_addr[2];	// IO space base address of MCU control
+};
+#endif /* JTAG3_PRIVATE_EXPORTED */
diff --git a/pgm_type.c b/pgm_type.c
index e0cc8311..4aadc001 100644
--- a/pgm_type.c
+++ b/pgm_type.c
@@ -37,6 +37,7 @@
 #include "ft245r.h"
 #include "jtagmkI.h"
 #include "jtagmkII.h"
+#include "jtag3.h"
 #include "par.h"
 #include "pickit2.h"
 #include "ppi.h"
@@ -69,6 +70,9 @@ const PROGRAMMER_TYPE const programmers_types[] = {
         {"jtagmkii_dw", jtagmkII_dw_initpgm, jtagmkII_dw_desc},
         {"jtagmkii_isp", stk500v2_jtagmkII_initpgm, stk500v2_jtagmkII_desc},
         {"jtagmkii_pdi", jtagmkII_pdi_initpgm, jtagmkII_pdi_desc},
+        {"jtagice3", jtag3_initpgm, jtag3_desc},
+        {"jtagice3_pdi", jtag3_pdi_initpgm, jtag3_pdi_desc},
+        {"jtagice3_dw", jtag3_dw_initpgm, jtag3_dw_desc},
         {"par", par_initpgm, par_desc},
         {"pickit2", pickit2_initpgm, pickit2_desc},
         {"serbb", serbb_initpgm, serbb_desc},
diff --git a/usb_libusb.c b/usb_libusb.c
index 86d969c7..35bdbfa4 100644
--- a/usb_libusb.c
+++ b/usb_libusb.c
@@ -52,7 +52,7 @@
 #  undef interface
 #endif
 
-static char usbbuf[USBDEV_MAX_XFER_MKII];
+static char usbbuf[USBDEV_MAX_XFER_3];
 static int buflen = -1, bufptr;
 
 static int usb_interface;
@@ -399,6 +399,32 @@ static int usbdev_recv_frame(union filedescriptor *fd, unsigned char *buf, size_
   int i;
   unsigned char * p = buf;
 
+  /* If there's an event EP, and it has data pending, return it first. */
+  if (fd->usb.eep != 0)
+  {
+      rv = usb_bulk_read(udev, fd->usb.eep, usbbuf,
+                         fd->usb.max_xfer, 1);
+      if (rv > 4)
+      {
+	  if (verbose >= 3)
+	  {
+	      unsigned short evtserial = (usbbuf[3] << 8) | usbbuf[2];
+	      fprintf(stderr, "Event serial # 0x%04x, replaced by 0xffff\n",
+		      evtserial);
+	  }
+	  usbbuf[3] = usbbuf[2] = 0xff;
+	  memcpy(buf, usbbuf + 2, rv - 2);
+	  n = rv - 2;
+	  goto printout;
+      }
+      else if (rv > 0)
+      {
+	  fprintf(stderr, "Short event len = %d, ignored.\n", rv);
+	  n = rv;
+	  goto printout;
+      }
+  }
+
   n = 0;
   do
     {
@@ -426,6 +452,7 @@ static int usbdev_recv_frame(union filedescriptor *fd, unsigned char *buf, size_
   if (nbytes < 0)
     return -1;
 
+  printout:
   if (verbose > 3)
   {
       i = n;
diff --git a/usbdevs.h b/usbdevs.h
index 6bbfbf16..e4523324 100644
--- a/usbdevs.h
+++ b/usbdevs.h
@@ -30,10 +30,17 @@
 #define USB_DEVICE_AVRISPMKII  0x2104
 #define USB_DEVICE_STK600      0x2106
 #define USB_DEVICE_AVRDRAGON   0x2107
+#define USB_DEVICE_JTAGICE3    0x2110
 
 /* JTAGICEmkII */
 #define USBDEV_BULK_EP_WRITE_MKII 0x02
 #define USBDEV_BULK_EP_READ_MKII  0x82
 #define USBDEV_MAX_XFER_MKII 64
 
+/* JTAGICE3 */
+#define USBDEV_BULK_EP_WRITE_3    0x01
+#define USBDEV_BULK_EP_READ_3     0x82
+#define USBDEV_EVT_EP_READ_3      0x83
+#define USBDEV_MAX_XFER_3    512
+
 #endif  /* usbdevs_h */