From 9839579e66946bdf32423fe92660b86a50b057b6 Mon Sep 17 00:00:00 2001
From: joerg_wunsch <joerg_wunsch@81a1dc3b-b13d-400b-aceb-764788c761c2>
Date: Tue, 10 May 2005 19:53:56 +0000
Subject: [PATCH] Oops, more files I forgot to add during the last commit.

git-svn-id: svn://svn.savannah.nongnu.org/avrdude/trunk/avrdude@453 81a1dc3b-b13d-400b-aceb-764788c761c2
---
 jtagmkII.c         | 1833 ++++++++++++++++++++++++++++++++++++++++++++
 jtagmkII.h         |   28 +
 jtagmkII_private.h |  296 +++++++
 3 files changed, 2157 insertions(+)
 create mode 100644 jtagmkII.c
 create mode 100644 jtagmkII.h
 create mode 100644 jtagmkII_private.h

diff --git a/jtagmkII.c b/jtagmkII.c
new file mode 100644
index 00000000..dca287a7
--- /dev/null
+++ b/jtagmkII.c
@@ -0,0 +1,1833 @@
+/*
+ * avrdude - A Downloader/Uploader for AVR device programmers
+ * Copyright (C) 2005 Joerg Wunsch <j@uriah.heep.sax.de>
+ *
+ * Derived from stk500 code which is:
+ * Copyright (C) 2002-2004 Brian S. Dean <bsd@bsdhome.com>
+ * Copyright (C) 2005 Erik Walthinsen
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+/* $Id$ */
+
+/*
+ * avrdude interface for Atmel JTAG ICE mkII programmer
+ */
+
+#include "ac_cfg.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+#include <sys/time.h>
+#include <time.h>
+
+#include "avr.h"
+#include "crc16.h"
+#include "pgm.h"
+#include "jtagmkII_private.h"
+#include "serial.h"
+
+
+extern int    verbose;
+extern char * progname;
+extern int do_cycles;
+
+/*
+ * XXX There should really be a programmer-specific private data
+ * pointer in struct PROGRAMMER.
+ */
+static unsigned short command_sequence; /* Next cmd seqno to issue. */
+
+/*
+ * See jtagmkII_read_byte() for an explanation of the flash and
+ * EEPROM page caches.
+ */
+static unsigned char *flash_pagecache;
+static unsigned long flash_pageaddr;
+static unsigned int flash_pagesize;
+
+static unsigned char *eeprom_pagecache;
+static unsigned long eeprom_pageaddr;
+static unsigned int eeprom_pagesize;
+
+static int prog_enabled;	/* Cached value of PROGRAMMING status. */
+static unsigned char serno[6];	/* JTAG ICE serial number. */
+/*
+ * The OCDEN fuse is bit 7 of the high fuse (hfuse).  In order to
+ * perform memory operations on MTYPE_SPM and MTYPE_EEPROM, we need to
+ * enable on-chip debugging, as these memory types are apparently
+ * emulated by running MCU instructions on the target MCU.  We cache
+ * the original value here, so it can be restored before exiting.
+ * User-requested hfuse updates will always mask out the OCDEN fuse
+ * then, only updating the cached copy.
+ *
+ * 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)
+static unsigned char hfuse_backup;
+static int internal_hfuse_handling;
+
+static int jtagmkII_read_byte(PROGRAMMER * pgm, AVRPART * p, AVRMEM * mem,
+			      unsigned long addr, unsigned char * value);
+static int jtagmkII_write_byte(PROGRAMMER * pgm, AVRPART * p, AVRMEM * mem,
+			       unsigned long addr, unsigned char data);
+static int jtagmkII_set_sck_period(PROGRAMMER * pgm, double v);
+static int jtagmkII_getparm(PROGRAMMER * pgm, unsigned char parm,
+			    unsigned char * value);
+static int jtagmkII_setparm(PROGRAMMER * pgm, unsigned char parm,
+			    unsigned char * value);
+static void jtagmkII_print_parms1(PROGRAMMER * pgm, char * p);
+
+static unsigned long
+b4_to_u32(unsigned char *b)
+{
+  unsigned long l;
+  l = b[0];
+  l += b[1] << 8;
+  l += b[2] << 16;
+  l += b[3] << 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 unsigned short
+b2_to_u16(unsigned char *b)
+{
+  unsigned short l;
+  l = b[0];
+  l += 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 jtagmkII_print_memory(unsigned char *b, size_t s)
+{
+  int i;
+
+  if (s < 2)
+    return;
+
+  for (i = 0; i < s - 1; i++) {
+    fprintf(stderr, "0x%02x ", b[i + 1]);
+    if (i % 16 == 15)
+      putc('\n', stderr);
+    else
+      putc(' ', stderr);
+  }
+  if (i % 16 != 0)
+    putc('\n', stderr);
+}
+
+static void jtagmkII_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, "0x%02x", data[i]);
+      if (i % 16 == 15)
+	putc('\n', stderr);
+      else
+	putchar(' ');
+    }
+    if (i % 16 != 0)
+      putc('\n', stderr);
+  }
+
+  switch (data[0]) {
+  case RSP_OK:
+    fprintf(stderr, "OK\n");
+    break;
+
+  case RSP_FAILED:
+    fprintf(stderr, "FAILED\n");
+    break;
+
+  case RSP_ILLEGAL_BREAKPOINT:
+    fprintf(stderr, "Illegal breakpoint\n");
+    break;
+
+  case RSP_ILLEGAL_COMMAND:
+    fprintf(stderr, "Illegal command\n");
+    break;
+
+  case RSP_ILLEGAL_EMULATOR_MODE:
+    fprintf(stderr, "Illegal emulator mode");
+    if (len > 1)
+      switch (data[1]) {
+      case EMULATOR_MODE_DEBUGWIRE: fprintf(stderr, ": DebugWire"); break;
+      case EMULATOR_MODE_JTAG:      fprintf(stderr, ": JTAG"); break;
+      case EMULATOR_MODE_UNKNOWN:   fprintf(stderr, ": Unknown"); break;
+      case EMULATOR_MODE_SPI:       fprintf(stderr, ": SPI"); break;
+      }
+    putc('\n', stderr);
+    break;
+
+  case RSP_ILLEGAL_JTAG_ID:
+    fprintf(stderr, "Illegal JTAG ID\n");
+    break;
+
+  case RSP_ILLEGAL_MCU_STATE:
+    fprintf(stderr, "Illegal MCU state");
+    if (len > 1)
+      switch (data[1]) {
+      case STOPPED:     fprintf(stderr, ": Stopped"); break;
+      case RUNNING:     fprintf(stderr, ": Running"); break;
+      case PROGRAMMING: fprintf(stderr, ": Programming"); break;
+      }
+    putc('\n', stderr);
+    break;
+
+  case RSP_ILLEGAL_MEMORY_TYPE:
+    fprintf(stderr, "Illegal memory type\n");
+    break;
+
+  case RSP_ILLEGAL_MEMORY_RANGE:
+    fprintf(stderr, "Illegal memory range\n");
+    break;
+
+  case RSP_ILLEGAL_PARAMETER:
+    fprintf(stderr, "Illegal parameter\n");
+    break;
+
+  case RSP_ILLEGAL_POWER_STATE:
+    fprintf(stderr, "Illegal power state\n");
+    break;
+
+  case RSP_ILLEGAL_VALUE:
+    fprintf(stderr, "Illegal value\n");
+    break;
+
+  case RSP_NO_TARGET_POWER:
+    fprintf(stderr, "No target power\n");
+    break;
+
+  case RSP_SIGN_ON:
+    fprintf(stderr, "Sign-on succeeded\n");
+    /* Sign-on data will be printed below anyway. */
+    break;
+
+  case RSP_MEMORY:
+    fprintf(stderr, "memory contents:\n");
+    jtagmkII_print_memory(data, len);
+    break;
+
+  case RSP_PARAMETER:
+    fprintf(stderr, "parameter values:\n");
+    jtagmkII_print_memory(data, len);
+    break;
+
+  case RSP_SPI_DATA:
+    fprintf(stderr, "SPI data returned:\n");
+    for (i = 1; i < len; i++)
+      fprintf(stderr, "0x%02x ", data[i]);
+    putc('\n', stderr);
+    break;
+
+  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;
+
+  default:
+    fprintf(stderr, "unknown message 0x%02x\n", data[0]);
+  }
+
+  putc('\n', stderr);
+}
+
+
+static int jtagmkII_send(PROGRAMMER * pgm, unsigned char * data, size_t len)
+{
+  unsigned char *buf;
+
+  if (verbose >= 3)
+    fprintf(stderr, "\n%s: jtagmkII_send(): sending %d bytes\n",
+	    progname, len);
+
+  if ((buf = malloc(len + 10)) == NULL)
+    {
+      fprintf(stderr, "%s: jtagmkII_send(): out of memory",
+	      progname);
+      return -1;
+    }
+
+  buf[0] = MESSAGE_START;
+  u16_to_b2(buf + 1, command_sequence);
+  u32_to_b4(buf + 3, len);
+  buf[7] = TOKEN;
+  memcpy(buf + 8, data, len);
+
+  crcappend(buf, len + 8);
+
+  if (serial_send(pgm->fd, buf, len + 10) != 0) {
+    fprintf(stderr,
+	    "%s: jtagmkII_send(): failed to send command to serial port\n",
+	    progname);
+    exit(1);
+  }
+
+  free(buf);
+
+  return 0;
+}
+
+
+static int jtagmkII_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 jtagmkII_recv_frame(PROGRAMMER * pgm, unsigned char **msg,
+			       unsigned short * seqno) {
+  enum states { sSTART,
+		/* NB: do NOT change the sequence of the following: */
+		sSEQNUM1, sSEQNUM2,
+		sSIZE1, sSIZE2, sSIZE3, sSIZE4,
+		sTOKEN,
+		sDATA,
+		sCSUM1, sCSUM2,
+		/* end NB */
+		sDONE
+  }  state = sSTART;
+  unsigned long msglen = 0, l = 0;
+  int headeridx = 0;
+  int timeout = 0;
+  int ignorpkt = 0;
+  int rv;
+  unsigned char c, *buf = NULL, header[8];
+  unsigned short r_seqno = 0;
+  unsigned short checksum = 0;
+
+  struct timeval tv;
+  double timeoutval = 5;	/* seconds */
+  double tstart, tnow;
+
+  if (verbose >= 3)
+    fprintf(stderr, "%s: jtagmkII_recv():\n", progname);
+
+  gettimeofday(&tv, NULL);
+  tstart = tv.tv_sec;
+
+  while ( (state != sDONE ) && (!timeout) ) {
+    if (state == sDATA) {
+      rv = 0;
+      if (ignorpkt) {
+	/* skip packet's contents */
+	for(l = 0; l < msglen; l++)
+	  rv += serial_recv(pgm->fd, &c, 1);
+      } else {
+	rv += serial_recv(pgm->fd, buf + 8, msglen);
+      }
+      if (rv != 0) {
+	timedout:
+	/* timeout in receive */
+	if (verbose > 1)
+	  fprintf(stderr,
+		  "%s: jtagmkII_recv(): Timeout receiving packet\n",
+		  progname);
+	free(buf);
+	return -1;
+      }
+    } else {
+      if (serial_recv(pgm->fd, &c, 1) != 0)
+	goto timedout;
+    }
+    checksum ^= c;
+
+    if (state < sDATA)
+      header[headeridx++] = c;
+
+    switch (state) {
+      case sSTART:
+        if (c == MESSAGE_START) {
+          state = sSEQNUM1;
+        } else {
+	  headeridx = 0;
+	}
+        break;
+      case sSEQNUM1:
+      case sSEQNUM2:
+	r_seqno >>= 8;
+	r_seqno |= (c << 8);
+	state++;
+	break;
+      case sSIZE1:
+      case sSIZE2:
+      case sSIZE3:
+      case sSIZE4:
+	msglen >>= 8;
+	msglen |= (c << 24);
+        state++;
+        break;
+      case sTOKEN:
+        if (c == TOKEN) {
+	  state = sDATA;
+	  if (msglen > MAX_MESSAGE) {
+	    fprintf(stderr,
+		    "%s: jtagmkII_recv(): msglen %lu exceeds max message "
+		    "size %u, ignoring message\n",
+		    progname, msglen, MAX_MESSAGE);
+	    ignorpkt++;
+	  } else if ((buf = malloc(msglen + 10)) == NULL) {
+	    fprintf(stderr, "%s: jtagmkII_recv(): out of memory\n",
+		    progname);
+	    ignorpkt++;
+	  } else {
+	    memcpy(buf, header, 8);
+	  }
+	} else {
+	  state = sSTART;
+	  headeridx = 0;
+	}
+        break;
+      case sDATA:
+	/* The entire payload has been read above. */
+	l = msglen + 8;
+        state = sCSUM1;
+        break;
+      case sCSUM1:
+      case sCSUM2:
+	buf[l++] = c;
+	if (state == sCSUM2) {
+	  if (crcverify(buf, msglen + 10)) {
+	    if (verbose >= 3)
+	      fprintf(stderr, "%s: jtagmkII_recv(): CRC OK",
+		      progname);
+	    state = sDONE;
+	  } else {
+	    fprintf(stderr, "%s: jtagmkII_recv(): checksum error\n",
+		    progname);
+	    free(buf);
+	    return -4;
+	  }
+	} else
+	  state++;
+        break;
+      default:
+        fprintf(stderr, "%s: jtagmkII_recv(): unknown state\n",
+                progname);
+	free(buf);
+        return -5;
+     }
+
+     gettimeofday(&tv, NULL);
+     tnow = tv.tv_sec;
+     if (tnow - tstart > timeoutval) {
+       fprintf(stderr, "%s: jtagmkII_recv_frame(): timeout\n",
+               progname);
+       return -1;
+     }
+
+  }
+  if (verbose >= 3)
+fprintf(stderr, "\n");
+
+  *seqno = r_seqno;
+  *msg = buf;
+
+  return msglen;
+}
+
+static int jtagmkII_recv(PROGRAMMER * pgm, unsigned char **msg) {
+  unsigned short r_seqno;
+  int rv;
+
+  for (;;) {
+    if ((rv = jtagmkII_recv_frame(pgm, msg, &r_seqno)) <= 0)
+      return rv;
+    if (verbose >= 3)
+      fprintf(stderr, "%s: jtagmkII_recv(): "
+	      "Got message seqno %d (command_sequence == %d)\n",
+	      progname, r_seqno, command_sequence);
+    if (r_seqno == command_sequence) {
+      if (++command_sequence == 0xffff)
+	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 + 8, rv);
+      return rv;
+    }
+    if (r_seqno == 0xffff) {
+      if (verbose >= 3)
+	fprintf(stderr, "%s: jtagmkII_recv(): got asynchronous event\n",
+		progname);
+    } else {
+      if (verbose >= 2)
+	fprintf(stderr, "%s: jtagmkII_recv(): "
+		"got wrong sequence number, %u != %u\n",
+		progname, r_seqno, command_sequence);
+    }
+    free(*msg);
+  }
+  return 0;
+}
+
+
+static int jtagmkII_getsync(PROGRAMMER * pgm) {
+  int tries;
+#define MAXTRIES 33
+  unsigned char buf[3], *resp, c = 0xff;
+  int status;
+
+  if (verbose >= 3)
+    fprintf(stderr, "%s: jtagmkII_getsync()\n", progname);
+
+  for (tries = 0; tries < MAXTRIES; tries++) {
+
+    /* Get the sign-on information. */
+    buf[0] = CMND_GET_SIGN_ON;
+    if (verbose >= 2)
+      fprintf(stderr, "%s: jtagmkII_getsync(): Sending sign-on command: ",
+	      progname);
+    jtagmkII_send(pgm, buf, 1);
+
+    status = jtagmkII_recv(pgm, &resp);
+    if (status <= 0) {
+	fprintf(stderr, "%s: jtagmkII_getsync(): sign-on command: "
+		"status %d\n",
+		progname, status);
+    } else if (verbose >= 3) {
+      putc('\n', stderr);
+      jtagmkII_prmsg(pgm, resp, status);
+    } else if (verbose == 2)
+      fprintf(stderr, "0x%02x (%d bytes msg)\n", resp[0], status);
+
+    if (status > 0) {
+      if ((c = resp[0]) == RSP_SIGN_ON) {
+	if (verbose >= 1 && status > 17) {
+	  fprintf(stderr, "JTAG ICE mkII sign-on message:\n");
+	  fprintf(stderr, "Communications protocol version: %u\n",
+		  (unsigned)resp[1]);
+	  fprintf(stderr, "M_MCU:\n");
+	  fprintf(stderr, "  boot-loader FW version:        %u\n",
+		  (unsigned)resp[2]);
+	  fprintf(stderr, "  firmware version:              %u.%02u\n",
+		  (unsigned)resp[4], (unsigned)resp[3]);
+	  fprintf(stderr, "  hardware version:              %u\n",
+		  (unsigned)resp[5]);
+	  fprintf(stderr, "S_MCU:\n");
+	  fprintf(stderr, "  boot-loader FW version:        %u\n",
+		  (unsigned)resp[6]);
+	  fprintf(stderr, "  firmware version:              %u.%02u\n",
+		  (unsigned)resp[8], (unsigned)resp[7]);
+	  fprintf(stderr, "  hardware version:              %u\n",
+		  (unsigned)resp[9]);
+	  memcpy(serno, resp + 10, 6);
+	  fprintf(stderr, "Serial number:                   "
+		  "%02x:%02x:%02x:%02x:%02x:%02x\n",
+		  serno[0], serno[1], serno[2], serno[3], serno[4], serno[5]);
+	  resp[status - 1] = '\0';
+	  fprintf(stderr, "Device ID:                       %s\n",
+		  resp + 16);
+	}
+	break;
+      }
+      free(resp);
+    }
+  }
+  if (tries >= MAXTRIES) {
+    if (status <= 0)
+      fprintf(stderr,
+	      "%s: jtagmkII_getsync(): "
+	      "timeout/error communicating with programmer (status %d)\n",
+	      progname, status);
+    else
+      fprintf(stderr,
+	      "%s: jtagmkII_getsync(): "
+	      "bad response to sign-on command: 0x%02x\n",
+	      progname, c);
+    return -1;
+  }
+
+  /* Turn the ICE into JTAG mode */
+  buf[0] = EMULATOR_MODE_JTAG;
+  if (jtagmkII_setparm(pgm, PAR_EMULATOR_MODE, buf) < 0)
+    return -1;
+
+  /* GET SYNC forces the target into STOPPED mode */
+  buf[0] = CMND_GET_SYNC;
+  if (verbose >= 2)
+    fprintf(stderr, "%s: jtagmkII_getsync(): Sending get sync command: ",
+	    progname);
+  jtagmkII_send(pgm, buf, 1);
+
+  status = jtagmkII_recv(pgm, &resp);
+  if (status <= 0) {
+    if (verbose >= 2)
+      putc('\n', stderr);
+    fprintf(stderr,
+	    "%s: jtagmkII_getsync(): "
+	    "timeout/error communicating with programmer (status %d)\n",
+	    progname, status);
+    return -1;
+  }
+  if (verbose >= 3) {
+    putc('\n', stderr);
+    jtagmkII_prmsg(pgm, resp, status);
+  } else if (verbose == 2)
+    fprintf(stderr, "0x%02x (%d bytes msg)\n", resp[0], status);
+  c = resp[0];
+  free(resp);
+  if (c != RSP_OK) {
+    fprintf(stderr,
+	    "%s: jtagmkII_getsync(): "
+	    "bad response to set parameter command: 0x%02x\n",
+	    progname, c);
+    return -1;
+  }
+
+  return 0;
+}
+
+static int jtagmkII_cmd(PROGRAMMER * pgm, unsigned char cmd[4],
+                        unsigned char res[4])
+{
+
+  fprintf(stderr, "%s: jtagmkII_command(): no direct SPI supported for JTAG\n",
+	  progname);
+  return -1;
+}
+
+
+/*
+ * issue the 'chip erase' command to the AVR device
+ */
+static int jtagmkII_chip_erase(PROGRAMMER * pgm, AVRPART * p)
+{
+  int status;
+  unsigned char buf[1], *resp, c;
+
+  buf[0] = CMND_CHIP_ERASE;
+  if (verbose >= 2)
+    fprintf(stderr, "%s: jtagmkII_chip_erase(): Sending chip erase command: ",
+	    progname);
+  jtagmkII_send(pgm, buf, 1);
+
+  status = jtagmkII_recv(pgm, &resp);
+  if (status <= 0) {
+    if (verbose >= 2)
+      putc('\n', stderr);
+    fprintf(stderr,
+	    "%s: jtagmkII_chip_erase(): "
+	    "timeout/error communicating with programmer (status %d)\n",
+	    progname, status);
+    return -1;
+  }
+  if (verbose >= 3) {
+    putc('\n', stderr);
+    jtagmkII_prmsg(pgm, resp, status);
+  } else if (verbose == 2)
+    fprintf(stderr, "0x%02x (%d bytes msg)\n", resp[0], status);
+  c = resp[0];
+  free(resp);
+  if (c != RSP_OK) {
+    fprintf(stderr,
+	    "%s: jtagmkII_chip_erase(): "
+	    "bad response to chip erase command: 0x%02x\n",
+	    progname, c);
+    return -1;
+  }
+
+  pgm->initialize(pgm, p);
+
+  return 0;
+}
+
+static void jtagmkII_set_devdescr(PROGRAMMER * pgm, AVRPART * p)
+{
+  int status;
+  unsigned char *resp, c;
+  LNODEID ln;
+  AVRMEM * m;
+  struct {
+    unsigned char cmd;
+    struct device_descriptor dd;
+  } sendbuf;
+
+  memset(&sendbuf, 0, sizeof sendbuf);
+  sendbuf.cmd = CMND_SET_DEVICE_DESCRIPTOR;
+  sendbuf.dd.ucSPMCRAddress = p->spmcr;
+  sendbuf.dd.ucRAMPZAddress = p->rampz;
+  sendbuf.dd.ucIDRAddress = p->idr;
+  sendbuf.dd.ucAllowFullPageBitstream =
+    (p->flags & AVRPART_ALLOWFULLPAGEBITSTREAM) != 0;
+  sendbuf.dd.EnablePageProgramming =
+    (p->flags & AVRPART_ENABLEPAGEPROGRAMMING) != 0;
+  for (ln = lfirst(p->mem); ln; ln = lnext(ln)) {
+    m = ldata(ln);
+    if (strcmp(m->desc, "flash") == 0) {
+      flash_pagesize = m->page_size;
+      u32_to_b4(sendbuf.dd.ulFlashSize, m->size);
+      u16_to_b2(sendbuf.dd.uiFlashPageSize, flash_pagesize);
+      u16_to_b2(sendbuf.dd.uiFlashpages, m->size / flash_pagesize);
+    } else if (strcmp(m->desc, "eeprom") == 0) {
+      sendbuf.dd.ucEepromPageSize = eeprom_pagesize = m->page_size;
+    }
+  }
+
+  if (verbose >= 2)
+    fprintf(stderr, "%s: jtagmkII_set_devdescr(): "
+	    "Sending set device descriptor command: ",
+	    progname);
+  jtagmkII_send(pgm, (unsigned char *)&sendbuf, sizeof sendbuf);
+
+  status = jtagmkII_recv(pgm, &resp);
+  if (status <= 0) {
+    if (verbose >= 2)
+      putc('\n', stderr);
+    fprintf(stderr,
+	    "%s: jtagmkII_set_devdescr(): "
+	    "timeout/error communicating with programmer (status %d)\n",
+	    progname, status);
+    return;
+  }
+  if (verbose >= 3) {
+    putc('\n', stderr);
+    jtagmkII_prmsg(pgm, resp, status);
+  } else if (verbose == 2)
+    fprintf(stderr, "0x%02x (%d bytes msg)\n", resp[0], status);
+  c = resp[0];
+  free(resp);
+  if (c != RSP_OK) {
+    fprintf(stderr,
+	    "%s: jtagmkII_set_devdescr(): "
+	    "bad response to set device descriptor command: 0x%02x\n",
+	    progname, c);
+  }
+}
+
+/*
+ * Reset the target.
+ */
+static int jtagmkII_reset(PROGRAMMER * pgm)
+{
+  int status;
+  unsigned char buf[1], *resp, c;
+
+  buf[0] = CMND_RESET;
+  if (verbose >= 2)
+    fprintf(stderr, "%s: jtagmkII_reset(): Sending reset command: ",
+	    progname);
+  jtagmkII_send(pgm, buf, 1);
+
+  status = jtagmkII_recv(pgm, &resp);
+  if (status <= 0) {
+    if (verbose >= 2)
+      putc('\n', stderr);
+    fprintf(stderr,
+	    "%s: jtagmkII_reset(): "
+	    "timeout/error communicating with programmer (status %d)\n",
+	    progname, status);
+    return -1;
+  }
+  if (verbose >= 3) {
+    putc('\n', stderr);
+    jtagmkII_prmsg(pgm, resp, status);
+  } else if (verbose == 2)
+    fprintf(stderr, "0x%02x (%d bytes msg)\n", resp[0], status);
+  c = resp[0];
+  free(resp);
+  if (c != RSP_OK) {
+    fprintf(stderr,
+	    "%s: jtagmkII_reset(): "
+	    "bad response to reset command: 0x%02x\n",
+	    progname, c);
+    return -1;
+  }
+
+  return 0;
+}
+
+static int jtagmkII_program_enable_dummy(PROGRAMMER * pgm, AVRPART * p)
+{
+
+  return 0;
+}
+
+static int jtagmkII_program_enable(PROGRAMMER * pgm)
+{
+  int status;
+  unsigned char buf[1], *resp, c;
+
+  if (prog_enabled)
+    return 0;
+
+  buf[0] = CMND_ENTER_PROGMODE;
+  if (verbose >= 2)
+    fprintf(stderr, "%s: jtagmkII_program_enable(): "
+	    "Sending enter progmode command: ",
+	    progname);
+  jtagmkII_send(pgm, buf, 1);
+
+  status = jtagmkII_recv(pgm, &resp);
+  if (status <= 0) {
+    if (verbose >= 2)
+      putc('\n', stderr);
+    fprintf(stderr,
+	    "%s: jtagmkII_program_enable(): "
+	    "timeout/error communicating with programmer (status %d)\n",
+	    progname, status);
+    return -1;
+  }
+  if (verbose >= 3) {
+    putc('\n', stderr);
+    jtagmkII_prmsg(pgm, resp, status);
+  } else if (verbose == 2)
+    fprintf(stderr, "0x%02x (%d bytes msg)\n", resp[0], status);
+  c = resp[0];
+  free(resp);
+  if (c != RSP_OK) {
+    fprintf(stderr,
+	    "%s: jtagmkII_program_enable(): "
+	    "bad response to enter progmode command: 0x%02x\n",
+	    progname, c);
+    return -1;
+  }
+
+  prog_enabled = 1;
+  return 0;
+}
+
+static int jtagmkII_program_disable(PROGRAMMER * pgm)
+{
+  int status;
+  unsigned char buf[1], *resp, c;
+
+  if (!prog_enabled)
+    return 0;
+
+  buf[0] = CMND_LEAVE_PROGMODE;
+  if (verbose >= 2)
+    fprintf(stderr, "%s: jtagmkII_program_disable(): "
+	    "Sending leave progmode command: ",
+	    progname);
+  jtagmkII_send(pgm, buf, 1);
+
+  status = jtagmkII_recv(pgm, &resp);
+  if (status <= 0) {
+    if (verbose >= 2)
+      putc('\n', stderr);
+    fprintf(stderr,
+	    "%s: jtagmkII_program_disable(): "
+	    "timeout/error communicating with programmer (status %d)\n",
+	    progname, status);
+    return -1;
+  }
+  if (verbose >= 3) {
+    putc('\n', stderr);
+    jtagmkII_prmsg(pgm, resp, status);
+  } else if (verbose == 2)
+    fprintf(stderr, "0x%02x (%d bytes msg)\n", resp[0], status);
+  c = resp[0];
+  free(resp);
+  if (c != RSP_OK) {
+    fprintf(stderr,
+	    "%s: jtagmkII_program_disable(): "
+	    "bad response to leave progmode command: 0x%02x\n",
+	    progname, c);
+    return -1;
+  }
+
+  prog_enabled = 0;
+  (void)jtagmkII_reset(pgm);
+
+  return 0;
+}
+
+static unsigned char jtagmkII_get_baud(long baud)
+{
+  static struct {
+    long baud;
+    unsigned char val;
+  } baudtab[] = {
+    { 2400L, BAUD_2400 },
+    { 4800L, BAUD_4800 },
+    { 9600L, BAUD_9600 },
+    { 19200L, BAUD_19200 },
+    { 38400L, BAUD_38400 },
+    { 57600L, BAUD_57600 },
+    { 115200L, BAUD_115200 },
+    { 14400L, BAUD_14400 },
+  };
+  int i;
+
+  for (i = 0; i < sizeof baudtab / sizeof baudtab[0]; i++)
+    if (baud == baudtab[i].baud)
+      return baudtab[i].val;
+
+  return 0;
+}
+
+/*
+ * initialize the AVR device and prepare it to accept commands
+ */
+static int jtagmkII_initialize(PROGRAMMER * pgm, AVRPART * p)
+{
+  AVRMEM hfuse;
+  unsigned char b;
+
+  if (!(p->flags & AVRPART_HAS_JTAG)) {
+    fprintf(stderr, "%s: jtagmkII_initialize(): part %s has no JTAG interface\n",
+	    progname, p->desc);
+    return -1;
+  }
+
+  if (pgm->baudrate && pgm->baudrate != 19200) {
+    if ((b = jtagmkII_get_baud(pgm->baudrate)) == 0) {
+      fprintf(stderr, "%s: jtagmkII_initialize(): unsupported baudrate %d\n",
+	      progname, pgm->baudrate);
+    } else {
+      if (verbose >= 2)
+	fprintf(stderr, "%s: jtagmkII_initialize(): "
+		"trying to set baudrate to %d\n",
+		progname, pgm->baudrate);
+      if (jtagmkII_setparm(pgm, PAR_BAUD_RATE, &b) == 0)
+	serial_setspeed(pgm->fd, pgm->baudrate);
+    }
+  }
+  if (pgm->bitclock != 0.0) {
+    if (verbose >= 2)
+      fprintf(stderr, "%s: jtagmkII_initialize(): "
+	      "trying to set JTAG clock period to %.1f us\n",
+	      progname, pgm->bitclock);
+    if (jtagmkII_set_sck_period(pgm, pgm->bitclock) != 0)
+      return -1;
+  }
+
+  /*
+   * Must set the device descriptor before entering programming mode.
+   */
+  jtagmkII_set_devdescr(pgm, p);
+
+  free(flash_pagecache);
+  free(eeprom_pagecache);
+  if ((flash_pagecache = malloc(flash_pagesize)) == NULL) {
+    fprintf(stderr, "%s: jtagmkII_initialize(): Out of memory\n",
+	    progname);
+    return -1;
+  }
+  if ((eeprom_pagecache = malloc(eeprom_pagesize)) == NULL) {
+    fprintf(stderr, "%s: jtagmkII_initialize(): Out of memory\n",
+	    progname);
+    free(flash_pagecache);
+    return -1;
+  }
+  flash_pageaddr = eeprom_pageaddr = (unsigned long)-1L;
+
+  if (jtagmkII_reset(pgm) < 0)
+    return -1;
+
+  internal_hfuse_handling = 1;
+  strcpy(hfuse.desc, "hfuse");
+  if (jtagmkII_read_byte(pgm, p, &hfuse, 1, &hfuse_backup) < 0) {
+    internal_hfuse_handling = 0;
+    return -1;
+  }
+  b = hfuse_backup;
+  b &= ~OCDEN;
+  if (jtagmkII_write_byte(pgm, p, &hfuse, 1, b) < 0) {
+    internal_hfuse_handling = 0;
+    return -1;
+  }
+  internal_hfuse_handling = 0;
+
+  return 0;
+}
+
+
+static void jtagmkII_disable(PROGRAMMER * pgm)
+{
+
+  free(flash_pagecache);
+  flash_pagecache = NULL;
+  free(eeprom_pagecache);
+  eeprom_pagecache = NULL;
+
+  (void)jtagmkII_program_disable(pgm);
+}
+
+static void jtagmkII_enable(PROGRAMMER * pgm)
+{
+  return;
+}
+
+
+static int jtagmkII_open(PROGRAMMER * pgm, char * port)
+{
+  if (verbose >= 2)
+    fprintf(stderr, "%s: jtagmkII_open()\n", progname);
+
+  strcpy(pgm->port, port);
+  /*
+   * The JTAG ICE mkII always starts with a baud rate of 19200 Bd upon
+   * attaching.  If the config file or command-line parameters specify
+   * a higher baud rate, we switch to it later on, after establishing
+   * the connection with the ICE.
+   */
+  pgm->fd = serial_open(port, 19200);
+
+  /*
+   * drain any extraneous input
+   */
+  jtagmkII_drain(pgm, 0);
+
+  jtagmkII_getsync(pgm);
+
+  return 0;
+}
+
+
+static void jtagmkII_close(PROGRAMMER * pgm)
+{
+  int status;
+  unsigned char buf[1], *resp, c;
+  AVRMEM hfuse;
+
+  if (verbose >= 2)
+    fprintf(stderr, "%s: jtagmkII_close()\n", progname);
+
+  internal_hfuse_handling = 1;
+  strcpy(hfuse.desc, "hfuse");
+  (void)jtagmkII_write_byte(pgm, NULL, &hfuse, 1, hfuse_backup);
+  internal_hfuse_handling = 0;
+
+  buf[0] = CMND_RESET;
+  if (verbose >= 2)
+    fprintf(stderr, "%s: jtagmkII_close(): Sending restore target command: ",
+	    progname);
+  jtagmkII_send(pgm, buf, 1);
+
+  status = jtagmkII_recv(pgm, &resp);
+  if (status <= 0) {
+    if (verbose >= 2)
+      putc('\n', stderr);
+    fprintf(stderr,
+	    "%s: jtagmkII_close(): "
+	    "timeout/error communicating with programmer (status %d)\n",
+	    progname, status);
+  } else {
+    if (verbose >= 3) {
+      putc('\n', stderr);
+      jtagmkII_prmsg(pgm, resp, status);
+    } else if (verbose == 2)
+      fprintf(stderr, "0x%02x (%d bytes msg)\n", resp[0], status);
+    c = resp[0];
+    free(resp);
+    if (c != RSP_OK) {
+      fprintf(stderr,
+	      "%s: jtagmkII_close(): "
+	      "bad response to restore target command: 0x%02x\n",
+	      progname, c);
+    }
+  }
+
+  buf[0] = CMND_GO;
+  if (verbose >= 2)
+    fprintf(stderr, "%s: jtagmkII_close(): Sending GO command: ",
+	    progname);
+  jtagmkII_send(pgm, buf, 1);
+
+  status = jtagmkII_recv(pgm, &resp);
+  if (status <= 0) {
+    if (verbose >= 2)
+      putc('\n', stderr);
+    fprintf(stderr,
+	    "%s: jtagmkII_close(): "
+	    "timeout/error communicating with programmer (status %d)\n",
+	    progname, status);
+  } else {
+    if (verbose >= 3) {
+      putc('\n', stderr);
+      jtagmkII_prmsg(pgm, resp, status);
+    } else if (verbose == 2)
+      fprintf(stderr, "0x%02x (%d bytes msg)\n", resp[0], status);
+    c = resp[0];
+    free(resp);
+    if (c != RSP_OK) {
+      fprintf(stderr,
+	      "%s: jtagmkII_close(): "
+	      "bad response to GO command: 0x%02x\n",
+	      progname, c);
+    }
+  }
+
+  buf[0] = CMND_SIGN_OFF;
+  if (verbose >= 2)
+    fprintf(stderr, "%s: jtagmkII_close(): Sending sign-off command: ",
+	    progname);
+  jtagmkII_send(pgm, buf, 1);
+
+  status = jtagmkII_recv(pgm, &resp);
+  if (status <= 0) {
+    if (verbose >= 2)
+      putc('\n', stderr);
+    fprintf(stderr,
+	    "%s: jtagmkII_close(): "
+	    "timeout/error communicating with programmer (status %d)\n",
+	    progname, status);
+    return;
+  }
+  if (verbose >= 3) {
+    putc('\n', stderr);
+    jtagmkII_prmsg(pgm, resp, status);
+  } else if (verbose == 2)
+    fprintf(stderr, "0x%02x (%d bytes msg)\n", resp[0], status);
+  c = resp[0];
+  free(resp);
+  if (c != RSP_OK) {
+    fprintf(stderr,
+	    "%s: jtagmkII_close(): "
+	    "bad response to sign-off command: 0x%02x\n",
+	    progname, c);
+  }
+
+  serial_close(pgm->fd);
+  pgm->fd = -1;
+}
+
+
+static int jtagmkII_paged_write(PROGRAMMER * pgm, AVRPART * p, AVRMEM * m,
+				int page_size, int n_bytes)
+{
+  int addr, block_size;
+  unsigned char *cmd;
+  unsigned char *resp;
+  int status, tries;
+  long otimeout = serial_recv_timeout;
+
+  if (verbose >= 2)
+    fprintf(stderr, "%s: jtagmkII_paged_write(.., %s, %d, %d)\n",
+	    progname, m->desc, page_size, n_bytes);
+
+  if (jtagmkII_program_enable(pgm) < 0)
+    return -1;
+
+  if ((cmd = malloc(page_size + 10)) == NULL) {
+    fprintf(stderr, "%s: jtagmkII_paged_write(): Out of memory\n",
+	    progname);
+    return -1;
+  }
+
+  cmd[0] = CMND_WRITE_MEMORY;
+  if (strcmp(m->desc, "flash") == 0) {
+    cmd[1] = MTYPE_FLASH_PAGE;
+    flash_pageaddr = (unsigned long)-1L;
+    page_size = flash_pagesize;
+  } else if (strcmp(m->desc, "eeprom") == 0) {
+    cmd[1] = MTYPE_EEPROM_PAGE;
+    eeprom_pageaddr = (unsigned long)-1L;
+    page_size = eeprom_pagesize;
+  }
+
+  if (page_size == 0) page_size = 256;
+
+  serial_recv_timeout = 100;
+  for (addr = 0; addr < n_bytes; addr += page_size) {
+    report_progress(addr, n_bytes,NULL);
+
+    if ((n_bytes-addr) < page_size)
+      block_size = n_bytes - addr;
+    else
+      block_size = page_size;
+    if (verbose >= 3)
+      fprintf(stderr, "%s: jtagmkII_paged_write(): "
+	      "block_size at addr %d is %d\n",
+	      progname, addr, block_size);
+
+    u32_to_b4(cmd + 2, page_size);
+    u32_to_b4(cmd + 6, addr);
+
+    /*
+     * 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 + 10, 0xff, page_size);
+    memcpy(cmd + 10, m->buf + addr, block_size);
+
+    tries = 0;
+
+    retry:
+    if (verbose >= 2)
+      fprintf(stderr, "%s: jtagmkII_paged_write(): "
+	      "Sending write memory command: ",
+	      progname);
+    jtagmkII_send(pgm, cmd, page_size + 10);
+
+    status = jtagmkII_recv(pgm, &resp);
+    if (status <= 0) {
+      if (verbose >= 2)
+	putc('\n', stderr);
+      if (verbose >= 1)
+	fprintf(stderr,
+		"%s: jtagmkII_paged_write(): "
+		"timeout/error communicating with programmer (status %d)\n",
+		progname, status);
+      if (tries++ < 3)
+	goto retry;
+      fprintf(stderr,
+	      "%s: jtagmkII_paged_write(): fatal timeout/"
+	      "error communicating with programmer (status %d)\n",
+	      progname, status);
+      free(cmd);
+      serial_recv_timeout = otimeout;
+      return -1;
+    }
+    if (verbose >= 3) {
+      putc('\n', stderr);
+      jtagmkII_prmsg(pgm, resp, status);
+    } else if (verbose == 2)
+      fprintf(stderr, "0x%02x (%d bytes msg)\n", resp[0], status);
+    if (resp[0] != RSP_OK) {
+      fprintf(stderr,
+	      "%s: jtagmkII_paged_write(): "
+	      "bad response to write memory command: 0x%02x\n",
+	      progname, resp[0]);
+      free(resp);
+      free(cmd);
+      serial_recv_timeout = otimeout;
+      return -1;
+    }
+    free(resp);
+  }
+
+  free(cmd);
+  serial_recv_timeout = otimeout;
+
+  return n_bytes;
+}
+
+static int jtagmkII_paged_load(PROGRAMMER * pgm, AVRPART * p, AVRMEM * m,
+			       int page_size, int n_bytes)
+{
+  int addr, block_size;
+  unsigned char cmd[10];
+  unsigned char *resp;
+  int status, tries;
+  long otimeout = serial_recv_timeout;
+
+  if (verbose >= 2)
+    fprintf(stderr, "%s: jtagmkII_paged_load(.., %s, %d, %d)\n",
+	    progname, m->desc, page_size, n_bytes);
+
+  if (jtagmkII_program_enable(pgm) < 0)
+    return -1;
+
+  page_size = m->readsize;
+
+  cmd[0] = CMND_READ_MEMORY;
+  if (strcmp(m->desc, "flash") == 0) {
+    cmd[1] = MTYPE_FLASH_PAGE;
+  } else if (strcmp(m->desc, "eeprom") == 0) {
+    cmd[1] = MTYPE_EEPROM_PAGE;
+  }
+
+  serial_recv_timeout = 100;
+  for (addr = 0; addr < n_bytes; addr += page_size) {
+    report_progress(addr, n_bytes,NULL);
+
+    if ((n_bytes-addr) < page_size)
+      block_size = n_bytes - addr;
+    else
+      block_size = page_size;
+    if (verbose >= 3)
+      fprintf(stderr, "%s: jtagmkII_paged_load(): "
+	      "block_size at addr %d is %d\n",
+	      progname, addr, block_size);
+
+    u32_to_b4(cmd + 2, block_size);
+    u32_to_b4(cmd + 6, addr);
+
+    tries = 0;
+
+    retry:
+    if (verbose >= 2)
+      fprintf(stderr, "%s: jtagmkII_paged_load(): Sending read memory command: ",
+	      progname);
+    jtagmkII_send(pgm, cmd, 10);
+
+    status = jtagmkII_recv(pgm, &resp);
+    if (status <= 0) {
+      if (verbose >= 2)
+	putc('\n', stderr);
+      if (verbose >= 1)
+	fprintf(stderr,
+		"%s: jtagmkII_paged_load(): "
+		"timeout/error communicating with programmer (status %d)\n",
+		progname, status);
+      if (tries++ < 3)
+	goto retry;
+      fprintf(stderr,
+	      "%s: jtagmkII_paged_load(): fatal timeout/"
+	      "error communicating with programmer (status %d)\n",
+	      progname, status);
+      serial_recv_timeout = otimeout;
+      return -1;
+    }
+    if (verbose >= 3) {
+      putc('\n', stderr);
+      jtagmkII_prmsg(pgm, resp, status);
+    } else if (verbose == 2)
+      fprintf(stderr, "0x%02x (%d bytes msg)\n", resp[0], status);
+    if (resp[0] != RSP_MEMORY) {
+      fprintf(stderr,
+	      "%s: jtagmkII_paged_load(): "
+	      "bad response to read memory command: 0x%02x\n",
+	      progname, resp[0]);
+      free(resp);
+      serial_recv_timeout = otimeout;
+      return -1;
+    }
+    memcpy(m->buf + addr, resp + 1, status);
+    free(resp);
+  }
+  serial_recv_timeout = otimeout;
+
+  return 0;
+}
+
+static int jtagmkII_read_byte(PROGRAMMER * pgm, AVRPART * p, AVRMEM * mem,
+			      unsigned long addr, unsigned char * value)
+{
+  unsigned char cmd[10];
+  unsigned char *resp = NULL, *cache_ptr = NULL;
+  int status, tries;
+  unsigned long paddr = 0UL, *paddr_ptr = NULL;
+  unsigned int pagesize = 0;
+
+  if (verbose >= 2)
+    fprintf(stderr, "%s: jtagmkII_read_byte(.., %s, 0x%lx, ...)\n",
+	    progname, mem->desc, addr);
+
+  if (jtagmkII_program_enable(pgm) < 0)
+    return -1;
+
+  cmd[0] = CMND_READ_MEMORY;
+
+  if (strcmp(mem->desc, "flash") == 0) {
+    cmd[1] = MTYPE_FLASH_PAGE;
+    pagesize = mem->page_size;
+    paddr = addr & ~(pagesize - 1);
+    paddr_ptr = &flash_pageaddr;
+    cache_ptr = flash_pagecache;
+  } else if (strcmp(mem->desc, "eeprom") == 0) {
+    cmd[1] = MTYPE_EEPROM_PAGE;
+    pagesize = mem->page_size;
+    paddr = addr & ~(pagesize - 1);
+    paddr_ptr = &eeprom_pageaddr;
+    cache_ptr = eeprom_pagecache;
+  } else if (strcmp(mem->desc, "lfuse") == 0) {
+    cmd[1] = MTYPE_FUSE_BITS;
+    addr = 0;
+  } else if (strcmp(mem->desc, "hfuse") == 0) {
+    cmd[1] = MTYPE_FUSE_BITS;
+    addr = 1;
+    if (!internal_hfuse_handling) {
+      *value = hfuse_backup;
+      return 0;
+    }
+  } else if (strcmp(mem->desc, "efuse") == 0) {
+    cmd[1] = MTYPE_FUSE_BITS;
+    addr = 2;
+  } else if (strcmp(mem->desc, "lock") == 0) {
+    cmd[1] = MTYPE_LOCK_BITS;
+  } else if (strcmp(mem->desc, "calibration") == 0) {
+    cmd[1] = MTYPE_OSCCAL_BYTE;
+  } else if (strcmp(mem->desc, "signature") == 0) {
+    cmd[1] = MTYPE_SIGN_JTAG;
+  }
+
+  /*
+   * 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 + 2, pagesize);
+    u32_to_b4(cmd + 6, paddr);
+  } else {
+    u32_to_b4(cmd + 2, 1);
+    u32_to_b4(cmd + 6, addr);
+  }
+
+  tries = 0;
+  retry:
+  if (verbose >= 2)
+    fprintf(stderr, "%s: jtagmkII_read_byte(): Sending read memory command: ",
+	    progname);
+  jtagmkII_send(pgm, cmd, 10);
+
+  status = jtagmkII_recv(pgm, &resp);
+  if (status <= 0) {
+    if (verbose >= 2)
+      putc('\n', stderr);
+    if (verbose >= 1)
+      fprintf(stderr,
+	      "%s: jtagmkII_read_byte(): "
+	      "timeout/error communicating with programmer (status %d)\n",
+	      progname, status);
+    if (tries++ < 3)
+      goto retry;
+    fprintf(stderr,
+	    "%s: jtagmkII_read_byte(): "
+	    "fatal timeout/error communicating with programmer (status %d)\n",
+	    progname, status);
+    goto fail;
+  }
+  if (verbose >= 3) {
+    putc('\n', stderr);
+    jtagmkII_prmsg(pgm, resp, status);
+  } else if (verbose == 2)
+    fprintf(stderr, "0x%02x (%d bytes msg)\n", resp[0], status);
+  if (resp[0] != RSP_MEMORY) {
+    fprintf(stderr,
+	    "%s: jtagmkII_read_byte(): "
+	    "bad response to read memory command: 0x%02x\n",
+	    progname, resp[0]);
+    goto fail;
+  }
+
+  if (pagesize) {
+    *paddr_ptr = paddr;
+    memcpy(cache_ptr, resp + 1, pagesize);
+    *value = cache_ptr[addr & (pagesize - 1)];
+  } else
+    *value = resp[1];
+
+  free(resp);
+  return 0;
+
+fail:
+  /*
+   * XXX should return an error status here, but that would cause
+   * the generic methods to retry the request using the SPI method,
+   * which is complete nonsense for JTAG.
+   */
+  *value = 42;
+  free(resp);
+  return 0;
+}
+
+static int jtagmkII_write_byte(PROGRAMMER * pgm, AVRPART * p, AVRMEM * mem,
+			       unsigned long addr, unsigned char data)
+{
+  unsigned char cmd[11];
+  unsigned char *resp = NULL, writedata;
+  int status, tries, need_progmode = 1, is_hfuse = 0;
+
+  if (verbose >= 2)
+    fprintf(stderr, "%s: jtagmkII_write_byte(.., %s, 0x%lx, ...)\n",
+	    progname, mem->desc, addr);
+
+  writedata = data;
+  cmd[0] = CMND_WRITE_MEMORY;
+  if (strcmp(mem->desc, "flash") == 0) {
+    cmd[1] = MTYPE_SPM;
+    need_progmode = 0;
+    flash_pageaddr = (unsigned long)-1L;
+  } else if (strcmp(mem->desc, "eeprom") == 0) {
+    cmd[1] = MTYPE_EEPROM;
+    need_progmode = 0;
+    eeprom_pageaddr = (unsigned long)-1L;
+  } else if (strcmp(mem->desc, "lfuse") == 0) {
+    cmd[1] = MTYPE_FUSE_BITS;
+    addr = 0;
+  } else if (strcmp(mem->desc, "hfuse") == 0) {
+    cmd[1] = MTYPE_FUSE_BITS;
+    addr = 1;
+    if (!internal_hfuse_handling) {
+      is_hfuse = 1;
+      writedata &= ~OCDEN;
+    }
+  } else if (strcmp(mem->desc, "efuse") == 0) {
+    cmd[1] = MTYPE_FUSE_BITS;
+    addr = 2;
+  } else if (strcmp(mem->desc, "lock") == 0) {
+    cmd[1] = MTYPE_LOCK_BITS;
+  } else if (strcmp(mem->desc, "calibration") == 0) {
+    cmd[1] = MTYPE_OSCCAL_BYTE;
+  } else if (strcmp(mem->desc, "signature") == 0) {
+    cmd[1] = MTYPE_SIGN_JTAG;
+  }
+
+  if (need_progmode) {
+    if (jtagmkII_program_enable(pgm) < 0)
+      return -1;
+  } else {
+    if (jtagmkII_program_disable(pgm) < 0)
+      return -1;
+  }
+
+  u32_to_b4(cmd + 2, 1);
+  u32_to_b4(cmd + 6, addr);
+  cmd[10] = writedata;
+
+  tries = 0;
+  retry:
+  if (verbose >= 2)
+    fprintf(stderr, "%s: jtagmkII_write_byte(): Sending write memory command: ",
+	    progname);
+  jtagmkII_send(pgm, cmd, 11);
+
+  status = jtagmkII_recv(pgm, &resp);
+  if (status <= 0) {
+    if (verbose >= 2)
+      putc('\n', stderr);
+    if (verbose > 1)
+      fprintf(stderr,
+	      "%s: jtagmkII_write_byte(): "
+	      "timeout/error communicating with programmer (status %d)\n",
+	      progname, status);
+    if (tries++ < 3)
+      goto retry;
+    fprintf(stderr,
+	    "%s: jtagmkII_write_byte(): "
+	    "fatal timeout/error communicating with programmer (status %d)\n",
+	    progname, status);
+    goto fail;
+  }
+  if (verbose >= 3) {
+    putc('\n', stderr);
+    jtagmkII_prmsg(pgm, resp, status);
+  } else if (verbose == 2)
+    fprintf(stderr, "0x%02x (%d bytes msg)\n", resp[0], status);
+  if (resp[0] != RSP_OK) {
+    fprintf(stderr,
+	    "%s: jtagmkII_write_byte(): "
+	    "bad response to write memory command: 0x%02x\n",
+	    progname, resp[0]);
+    goto fail;
+  }
+
+  if (is_hfuse && !internal_hfuse_handling)
+    hfuse_backup = data;
+  free(resp);
+  return 0;
+
+fail:
+  /*
+   * XXX should return an error status here, but that would cause
+   * the generic methods to retry the request using the SPI method,
+   * which is complete nonsense for JTAG.
+   */
+  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 jtagmkII_set_sck_period(PROGRAMMER * pgm, double v)
+{
+  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 jtagmkII_setparm(pgm, PAR_OCD_JTAG_CLK, &dur);
+}
+
+
+/*
+ * Read an emulator parameter.  As the maximal parameter length is 4
+ * bytes by now, we always copy out 4 bytes to *value, so the caller
+ * must have allocated sufficient space.
+ */
+static int jtagmkII_getparm(PROGRAMMER * pgm, unsigned char parm,
+			    unsigned char * value)
+{
+  int status;
+  unsigned char buf[2], *resp, c;
+
+  if (verbose >= 2)
+    fprintf(stderr, "%s: jtagmkII_getparm()\n", progname);
+
+  buf[0] = CMND_GET_PARAMETER;
+  buf[1] = parm;
+  if (verbose >= 2)
+    fprintf(stderr, "%s: jtagmkII_getparm(): "
+	    "Sending get parameter command (parm 0x%02x): ",
+	    progname, parm);
+  jtagmkII_send(pgm, buf, 2);
+
+  status = jtagmkII_recv(pgm, &resp);
+  if (status <= 0) {
+    if (verbose >= 2)
+      putc('\n', stderr);
+    fprintf(stderr,
+	    "%s: jtagmkII_getparm(): "
+	    "timeout/error communicating with programmer (status %d)\n",
+	    progname, status);
+    return -1;
+  }
+  if (verbose >= 3) {
+    putc('\n', stderr);
+    jtagmkII_prmsg(pgm, resp, status);
+  } else if (verbose == 2)
+    fprintf(stderr, "0x%02x (%d bytes msg)\n", resp[0], status);
+  c = resp[0];
+  if (c != RSP_PARAMETER) {
+    fprintf(stderr,
+	    "%s: jtagmkII_getparm(): "
+	    "bad response to get parameter command: 0x%02x\n",
+	    progname, c);
+    free(resp);
+    return -1;
+  }
+
+  memcpy(value, resp + 1, 4);
+  free(resp);
+
+  return 0;
+}
+
+/*
+ * Write an emulator parameter.
+ */
+static int jtagmkII_setparm(PROGRAMMER * pgm, unsigned char parm,
+			    unsigned char * value)
+{
+  int status;
+  /*
+   * As the maximal parameter length is 4 bytes, we use a fixed-length
+   * buffer, as opposed to malloc()ing it.
+   */
+  unsigned char buf[2 + 4], *resp, c;
+  size_t size;
+
+  if (verbose >= 2)
+    fprintf(stderr, "%s: jtagmkII_setparm()\n", progname);
+
+  switch (parm) {
+  case PAR_HW_VERSION: size = 2; break;
+  case PAR_FW_VERSION: size = 4; break;
+  case PAR_EMULATOR_MODE: size = 1; break;
+  case PAR_BAUD_RATE: size = 1; break;
+  case PAR_OCD_VTARGET: size = 2; break;
+  case PAR_OCD_JTAG_CLK: size = 1; break;
+  default:
+    fprintf(stderr, "%s: jtagmkII_setparm(): unknown parameter 0x%02x\n",
+	    progname, parm);
+    return -1;
+  }
+
+  buf[0] = CMND_SET_PARAMETER;
+  buf[1] = parm;
+  memcpy(buf + 2, value, size);
+  if (verbose >= 2)
+    fprintf(stderr, "%s: jtagmkII_setparm(): "
+	    "Sending set parameter command (parm 0x%02x, %u bytes): ",
+	    progname, parm, size);
+  jtagmkII_send(pgm, buf, size + 2);
+
+  status = jtagmkII_recv(pgm, &resp);
+  if (status <= 0) {
+    if (verbose >= 2)
+      putc('\n', stderr);
+    fprintf(stderr,
+	    "%s: jtagmkII_setparm(): "
+	    "timeout/error communicating with programmer (status %d)\n",
+	    progname, status);
+    return -1;
+  }
+  if (verbose >= 3) {
+    putc('\n', stderr);
+    jtagmkII_prmsg(pgm, resp, status);
+  } else if (verbose == 2)
+    fprintf(stderr, "0x%02x (%d bytes msg)\n", resp[0], status);
+  c = resp[0];
+  free(resp);
+  if (c != RSP_OK) {
+    fprintf(stderr,
+	    "%s: jtagmkII_setparm(): "
+	    "bad response to set parameter command: 0x%02x\n",
+	    progname, c);
+    return -1;
+  }
+
+  return 0;
+}
+
+
+static void jtagmkII_display(PROGRAMMER * pgm, char * p)
+{
+  unsigned char hw[4], fw[4];
+
+  if (jtagmkII_getparm(pgm, PAR_HW_VERSION, hw) < 0 ||
+      jtagmkII_getparm(pgm, PAR_FW_VERSION, fw) < 0)
+    return;
+
+  fprintf(stderr, "%sM_MCU hardware version: %d\n", p, hw[0]);
+  fprintf(stderr, "%sM_MCU firmware version: %d.%02d\n", p, fw[1], fw[0]);
+  fprintf(stderr, "%sS_MCU hardware version: %d\n", p, hw[1]);
+  fprintf(stderr, "%sS_MCU firmware version: %d.%02d\n", p, fw[3], fw[2]);
+  fprintf(stderr, "%sSerial number:          %02x:%02x:%02x:%02x:%02x:%02x\n",
+	  p, serno[0], serno[1], serno[2], serno[3], serno[4], serno[5]);
+
+  jtagmkII_print_parms1(pgm, p);
+
+  return;
+}
+
+
+static void jtagmkII_print_parms1(PROGRAMMER * pgm, char * p)
+{
+  unsigned char vtarget[4], jtag_clock[4];
+  char clkbuf[20];
+  double clk;
+
+  if (jtagmkII_getparm(pgm, PAR_OCD_VTARGET, vtarget) < 0 ||
+      jtagmkII_getparm(pgm, PAR_OCD_JTAG_CLK, jtag_clock) < 0)
+    return;
+
+  if (jtag_clock[0] == 0) {
+    strcpy(clkbuf, "6.4 MHz");
+    clk = 6.4e6;
+  } else if (jtag_clock[0] == 1) {
+    strcpy(clkbuf, "2.8 MHz");
+    clk = 2.8e6;
+  } else if (jtag_clock[0] <= 5) {
+    sprintf(clkbuf, "%.1f MHz", 5.35 / (double)jtag_clock[0]);
+    clk = 5.35e6 / (double)jtag_clock[0];
+  } else {
+    sprintf(clkbuf, "%.1f kHz", 5.35e3 / (double)jtag_clock[0]);
+    clk = 5.35e6 / (double)jtag_clock[0];
+  }
+
+  fprintf(stderr, "%sVtarget         : %.1f V\n", p,
+	  b2_to_u16(vtarget) / 1000.0);
+  fprintf(stderr, "%sJTAG clock      : %s (%.1f us)\n", p, clkbuf,
+	  1.0e6 / clk);
+
+  return;
+}
+
+
+static void jtagmkII_print_parms(PROGRAMMER * pgm)
+{
+  jtagmkII_print_parms1(pgm, "");
+}
+
+
+void jtagmkII_initpgm(PROGRAMMER * pgm)
+{
+  strcpy(pgm->type, "JTAGMKII");
+
+  /*
+   * mandatory functions
+   */
+  pgm->initialize     = jtagmkII_initialize;
+  pgm->display        = jtagmkII_display;
+  pgm->enable         = jtagmkII_enable;
+  pgm->disable        = jtagmkII_disable;
+  pgm->program_enable = jtagmkII_program_enable_dummy;
+  pgm->chip_erase     = jtagmkII_chip_erase;
+  pgm->cmd            = jtagmkII_cmd;
+  pgm->open           = jtagmkII_open;
+  pgm->close          = jtagmkII_close;
+
+  /*
+   * optional functions
+   */
+  pgm->paged_write    = jtagmkII_paged_write;
+  pgm->paged_load     = jtagmkII_paged_load;
+  pgm->read_byte      = jtagmkII_read_byte;
+  pgm->write_byte     = jtagmkII_write_byte;
+  pgm->print_parms    = jtagmkII_print_parms;
+  pgm->set_sck_period = jtagmkII_set_sck_period;
+  pgm->page_size      = 256;
+}
diff --git a/jtagmkII.h b/jtagmkII.h
new file mode 100644
index 00000000..c8b6e0aa
--- /dev/null
+++ b/jtagmkII.h
@@ -0,0 +1,28 @@
+/*
+ * avrdude - A Downloader/Uploader for AVR device programmers
+ * Copyright (C) 2002-2004  Brian S. Dean <bsd@bsdhome.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+/* $Id$ */
+
+#ifndef jtagmkII_h
+#define jtagmkII_h
+
+void jtagmkII_initpgm (PROGRAMMER * pgm);
+
+#endif
+
diff --git a/jtagmkII_private.h b/jtagmkII_private.h
new file mode 100644
index 00000000..6558a824
--- /dev/null
+++ b/jtagmkII_private.h
@@ -0,0 +1,296 @@
+/*
+ * avrdude - A Downloader/Uploader for AVR device programmers
+ * Copyright (C) 2005 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+/* $Id$ */
+
+
+/*
+ * JTAG ICE mkII definitions
+ * Taken from Appnote AVR067
+ */
+
+/*
+ * Communication with the JTAG ICE works in frames.  The protocol
+ * somewhat resembles the STK500v2 protocol, yet it is sufficiently
+ * different to prevent a direct code reuse. :-(
+ *
+ * Frame format:
+ *
+ *  +---------------------------------------------------------------+
+ *  |   0   |  1  .  2  |  3 . 4 . 5 . 6  |   7   | ... | N-1 .  N  |
+ *  |       |           |                 |       |     |           |
+ *  | start | LSB   MSB | LSB ....... MSB | token | msg | LSB   MSB |
+ *  | 0x1B  | sequence# | message size    | 0x0E  |     |   CRC16   |
+ *  +---------------------------------------------------------------+
+ *
+ * Each request message will be returned by a response with a matching
+ * sequence #.  Sequence # 0xffff is reserved for asynchronous event
+ * notifications that will be sent by the ICE without a request
+ * message (e.g. when the target hit a breakpoint).
+ *
+ * The message size excludes the framing overhead (10 bytes).
+ *
+ * The first byte of the message is always the request or response
+ * code, which is roughly classified as:
+ *
+ * . Messages (commands) use 0x00 through 0x3f.  (The documentation
+ *   claims that messages start at 0x01, but actually CMND_SIGN_OFF is
+ *   0x00.)
+ * . Internal commands use 0x40 through 0x7f (not documented).
+ * . Success responses use 0x80 through 0x9f.
+ * . Failure responses use 0xa0 through 0xbf.
+ * . Events use 0xe0 through 0xff.
+ */
+#define MESSAGE_START 0x1b
+#define TOKEN 0x0e
+
+/*
+ * Max message size we are willing to accept.  Prevents us from trying
+ * to allocate too much VM in case we received a nonsensical packet
+ * length.  We have to allocate the buffer as soon as we've got the
+ * length information (and thus have to trust that information by that
+ * time at first), as the final CRC check can only be done once the
+ * entire packet came it.
+ */
+#define MAX_MESSAGE 100000
+
+/* ICE command codes */
+#define CMND_CHIP_ERASE 0x13
+#define CMND_CLEAR_EVENTS 0x22
+#define CMND_CLR_BREAK 0x1A
+#define CMND_ENTER_PROGMODE 0x14
+#define CMND_ERASEPAGE_SPM 0x0D
+#define CMND_FORCED_STOP 0x0A
+#define CMND_GET_BREAK 0x12
+#define CMND_GET_PARAMETER 0x03
+#define CMND_GET_SIGN_ON 0x01
+#define CMND_GET_SYNC 0x0f
+#define CMND_GO 0x08
+#define CMND_LEAVE_PROGMODE 0x15
+#define CMND_READ_MEMORY 0x05
+#define CMND_READ_PC 0x07
+#define CMND_RESET 0x0B
+#define CMND_RESTORE_TARGET 0x23
+#define CMND_RUN_TO_ADDR 0x1C
+#define CMND_SELFTEST 0x10
+#define CMND_SET_BREAK 0x11
+#define CMND_SET_DEVICE_DESCRIPTOR 0x0C
+#define CMND_SET_N_PARAMETERS 0x16
+#define CMND_SET_PARAMETER 0x02
+#define CMND_SIGN_OFF 0x00
+#define CMND_SINGLE_STEP 0x09
+#define CMND_SPI_CMD 0x1D
+#define CMND_WRITE_MEMORY 0x04
+#define CMND_WRITE_PC 0x06
+
+/* ICE responses */
+#define RSP_DEBUGWIRE_SYNC_FAILED 0xAC
+#define RSP_FAILED 0xA0
+#define RSP_GET_BREAK 0x83
+#define RSP_ILLEGAL_BREAKPOINT 0xA8
+#define RSP_ILLEGAL_COMMAND 0xAA
+#define RSP_ILLEGAL_EMULATOR_MODE 0xA4
+#define RSP_ILLEGAL_JTAG_ID 0xA9
+#define RSP_ILLEGAL_MCU_STATE 0xA5
+#define RSP_ILLEGAL_MEMORY_TYPE 0xA2
+#define RSP_ILLEGAL_MEMORY_RANGE 0xA3
+#define RSP_ILLEGAL_PARAMETER 0xA1
+#define RSP_ILLEGAL_POWER_STATE 0xAD
+#define RSP_ILLEGAL_VALUE 0xA6
+#define RSP_MEMORY 0x82
+#define RSP_NO_TARGET_POWER 0xAB
+#define RSP_OK 0x80
+#define RSP_PARAMETER 0x81
+#define RSP_PC 0x84
+#define RSP_SELFTEST 0x85
+#define RSP_SET_N_PARAMETERS 0xA7
+#define RSP_SIGN_ON 0x86
+#define RSP_SPI_DATA 0x88
+
+/* ICE events */
+#define EVT_BREAK 0xE0
+#define EVT_DEBUG 0xE6
+#define EVT_ERROR_PHY_FORCE_BREAK_TIMEOUT 0xE2
+#define EVT_ERROR_PHY_MAX_BIT_LENGTH_DIFF 0xED
+#define EVT_ERROR_PHY_OPT_RECEIVE_TIMEOUT 0xF9
+#define EVT_ERROR_PHY_OPT_RECEIVED_BREAK 0xFA
+#define EVT_ERROR_PHY_RECEIVED_BREAK 0xF8
+#define EVT_ERROR_PHY_RECEIVE_TIMEOUT 0xF7
+#define EVT_ERROR_PHY_RELEASE_BREAK_TIMEOUT 0xE3
+#define EVT_ERROR_PHY_SYNC_OUT_OF_RANGE 0xF5
+#define EVT_ERROR_PHY_SYNC_TIMEOUT 0xF0
+#define EVT_ERROR_PHY_SYNC_TIMEOUT_BAUD 0xF4
+#define EVT_ERROR_PHY_SYNC_WAIT_TIMEOUT 0xF6
+#define EVT_RESULT_PHY_NO_ACTIVITY 0xFB
+#define EVT_EXT_RESET 0xE7
+#define EVT_ICE_POWER_ERROR_STATE 0xEA
+#define EVT_ICE_POWER_OK 0xEB
+#define EVT_IDR_DIRTY 0xEC
+#define EVT_NONE 0xEF
+#define EVT_PDSB_BREAK 0xF2
+#define EVT_PDSMB_BREAK 0xF3
+#define EVT_PROGRAM_BREAK 0xF1
+#define EVT_RUN 0xE1
+#define EVT_TARGET_POWER_OFF 0xE5
+#define EVT_TARGET_POWER_ON 0xE4
+#define EVT_TARGET_SLEEP 0xE8
+#define EVT_TARGET_WAKEUP 0xE9
+
+/* memory types for CMND_{READ,WRITE}_MEMORY */
+#define MTYPE_IO_SHADOW 0x30	/* cached IO registers? */
+#define MTYPE_SRAM 0x20		/* target's SRAM or [ext.] IO registers */
+#define MTYPE_EEPROM 0x22	/* EEPROM, what way? */
+#define MTYPE_EVENT 0x60	/* ICE event memory */
+#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_CAN 0xB6		/* CAN mailbox */
+
+/* (some) ICE parameters, for CMND_{GET,SET}_PARAMETER */
+#define PAR_HW_VERSION 0x01
+#define PAR_FW_VERSION 0x02
+#define PAR_EMULATOR_MODE 0x03
+# define EMULATOR_MODE_DEBUGWIRE 0x00
+# define EMULATOR_MODE_JTAG 0x01
+# define EMULATOR_MODE_UNKNOWN 0x02
+# define EMULATOR_MODE_SPI 0x03
+#define PAR_IREG 0x04
+#define PAR_BAUD_RATE 0x05
+# define BAUD_2400 0x01
+# define BAUD_4800 0x02
+# define BAUD_9600 0x03
+# define BAUD_19200 0x04	/* default */
+# define BAUD_38400 0x05
+# define BAUD_57600 0x06
+# define BAUD_115200 0x07
+# define BAUD_14400 0x08
+#define PAR_OCD_VTARGET 0x06
+#define PAR_OCD_JTAG_CLK 0x07
+#define PAR_OCD_BREAK_CAUSE 0x08
+#define PAR_TIMERS_RUNNING 0x09
+#define PAR_BREAK_ON_CHANGE_FLOW 0x0A
+#define PAR_BREAK_ADDR1 0x0B
+#define PAR_BREAK_ADDR2 0x0C
+#define PAR_COMBBREAKCTRL 0x0D
+#define PAR_JTAGID 0x0E
+#define PAR_UNITS_BEFORE 0x0F
+#define PAR_UNITS_AFTER 0x10
+#define PAR_BIT_BEFORE 0x11
+#define PAR_BIT_ATER 0x12
+#define PAR_EXTERNAL_RESET 0x13
+#define PAR_FLASH_PAGE_SIZE 0x14
+#define PAR_EEPROM_PAGE_SIZE 0x15
+#define PAR_UNUSED1 0x16
+#define PAR_PSB0 0x17
+#define PAR_PSB1 0x18
+#define PAR_PROTOCOL_DEBUG_EVENT 0x19
+#define PAR_MCU_STATE 0x1A
+# define STOPPED 0x00
+# define RUNNING 0x01
+# define PROGRAMMING 0x02
+#define PAR_DAISY_CHAIN_INFO 0x1B
+#define PAR_BOOT_ADDRESS 0x1C
+#define PAR_TARGET_SIGNATURE 0x1D
+#define PAR_DEBUGWIRE_BAUDRATE 0x1E
+#define PAR_PROGRAM_ENTRY_POINT 0x1F
+#define PAR_PACKET_PARSING_ERRORS 0x40
+#define PAR_VALID_PACKETS_RECEIVED 0x41
+#define PAR_INTERCOMMUNICATION_TX_FAILURES 0x42
+#define PAR_INTERCOMMUNICATION_RX_FAILURES 0x43
+#define PAR_CRC_ERRORS 0x44
+#define PAR_POWER_SOURCE 0x45
+# define POWER_EXTERNAL 0x00
+# define POWER_USB 0x01
+#define PAR_CAN_FLAG 0x22
+# define DONT_READ_CAN_MAILBOX 0x00
+# define READ_CAN_MAILBOX 0x01
+#define PAR_ENABLE_IDR_IN_RUN_MODE 0x23
+# define ACCESS_OSCCAL 0x00
+# define ACCESS_IDR 0x01
+#define PAR_ALLOW_PAGEPROGRAMMING_IN_SCANCHAIN 0x24
+# define PAGEPROG_NOT_ALLOWED 0x00
+# define PAGEPROG_ALLOWED 0x01
+
+/*
+ * In appnote AVR067, struct device_descriptor is written with
+ * int/long field types.  We cannot use them directly, as they were
+ * neither properly aligned for portability, nor did they care for
+ * endianess issues.  We thus use arrays of unsigned chars, plus
+ * conversion macros.
+ */
+struct device_descriptor
+{
+  unsigned char ucReadIO[8]; /*LSB = IOloc 0, MSB = IOloc63 */
+  unsigned char ucReadIOShadow[8]; /*LSB = IOloc 0, MSB = IOloc63 */
+  unsigned char ucWriteIO[8]; /*LSB = IOloc 0, MSB = IOloc63 */
+  unsigned char ucWriteIOShadow[8]; /*LSB = IOloc 0, MSB = IOloc63 */
+  unsigned char ucReadExtIO[52]; /*LSB = IOloc 96, MSB = IOloc511 */
+  unsigned char ucReadIOExtShadow[52]; /*LSB = IOloc 96, MSB = IOloc511 */
+  unsigned char ucWriteExtIO[52]; /*LSB = IOloc 96, MSB = IOloc511 */
+  unsigned char ucWriteIOExtShadow[52];/*LSB = IOloc 96, MSB = IOloc511 */
+  unsigned char ucIDRAddress; /*IDR address */
+  unsigned char ucSPMCRAddress; /*SPMCR Register address and dW BasePC */
+  unsigned char ucRAMPZAddress; /*RAMPZ Register address in SRAM I/O */
+				/*space */
+  unsigned char uiFlashPageSize[2]; /*Device Flash Page Size, Size = */
+				/*2 exp ucFlashPageSize */
+  unsigned char ucEepromPageSize; /*Device Eeprom Page Size in bytes */
+  unsigned char ulBootAddress[4]; /*Device Boot Loader Start Address */
+  unsigned char uiUpperExtIOLoc[2]; /*Topmost (last) extended I/O */
+				/*location, 0 if no external I/O */
+  unsigned char ulFlashSize[4]; /*Device Flash Size */
+  unsigned char ucEepromInst[20]; /*Instructions for W/R EEPROM */
+  unsigned char ucFlashInst[3]; /*Instructions for W/R FLASH */
+  unsigned char ucSPHaddr; /* stack pointer high */
+  unsigned char ucSPLaddr; /* stack pointer low */
+  /* new as of 16-02-2004 */
+  unsigned char uiFlashpages[2]; /* number of pages in flash */
+  unsigned char ucDWDRAddress; /* DWDR register address */
+  unsigned char ucDWBasePC; /* base/mask value of the PC */
+  /* new as of 30-04-2004 */
+  unsigned char ucAllowFullPageBitstream; /* FALSE on ALL new */
+				/*parts */
+  unsigned char uiStartSmallestBootLoaderSection[2]; /* */
+  /* new as of 18-10-2004 */
+  unsigned char EnablePageProgramming; /* For JTAG parts only, */
+				/* default TRUE */
+  unsigned char ucCacheType;	/* CacheType_Normal 0x00, */
+				/* CacheType_CAN 0x01, */
+				/* CacheType_HEIMDALL 0x02 */
+				/* new as of 27-10-2004 */
+  unsigned char uiSramStartAddr[2]; /* Start of SRAM */
+  unsigned char ucResetType; /* Selects reset type. ResetNormal = 0x00 */
+                             /* ResetAT76CXXX = 0x01 */
+  unsigned char ucPCMaskExtended; /* For parts with extended PC */
+  unsigned char ucPCMaskHigh; /* PC high mask */
+  unsigned char ucEindAddress; /* Selects reset type. [EIND address...] */
+  /* Does not work yet, M_MCU f/w rev 3.11, S_MCU f/w rev 3.16 */
+  /*  unsigned char EECRAddress[2]; */ /* EECR IO address */
+};
+
+#define fill_b4(u) \
+{ ((u) & 0xffUL), (((u) & 0xff00UL) >> 8), \
+  (((u) & 0xff0000UL) >> 16), (((u) & 0xff000000UL) >> 24) }
+#define fill_b2(u) \
+{ ((u) & 0xff), (((u) & 0xff00) >> 8) }