diff --git a/avrdude/avrdude.conf.in b/avrdude/avrdude.conf.in
index 824cc675..0ea49cf2 100644
--- a/avrdude/avrdude.conf.in
+++ b/avrdude/avrdude.conf.in
@@ -67,6 +67,8 @@
 #       idr              = <num> ;                # IO addr of IDR (OCD) reg.
 #       rampz            = <num> ;                # IO addr of RAMPZ reg.
 #       spmcr            = <num> ;                # mem addr of SPMC[S]R reg.
+#       eecr             = <num> ;                # mem addr of EECR reg.
+#                                                 # (only when != 0x3c)
 #
 #       memory <memtype>
 #           paged           = <yes/no> ;          # yes / no
@@ -2051,6 +2053,7 @@ part
     idr                 = 0x31;
     spmcr               = 0x57;
     rampz               = 0x3b;
+    eecr                = 0x3f;
 
     memory "eeprom"
         paged           = no; /* leave this "no" */
diff --git a/avrdude/avrpart.c b/avrdude/avrpart.c
index 78e112ce..612da347 100644
--- a/avrdude/avrpart.c
+++ b/avrdude/avrpart.c
@@ -366,7 +366,7 @@ AVRPART * avr_new_part(void)
   p->desc[0] = 0;
   p->reset_disposition = RESET_DEDICATED;
   p->retry_pulse = PIN_AVR_SCK;
-  p->flags = AVRPART_SERIALOK | AVRPART_PARALLELOK;
+  p->flags = AVRPART_SERIALOK | AVRPART_PARALLELOK | AVRPART_ENABLEPAGEPROGRAMMING;
   p->config_file[0] = 0;
   p->lineno = 0;
 
diff --git a/avrdude/avrpart.h b/avrdude/avrpart.h
index 138a6ebb..8cd644c3 100644
--- a/avrdude/avrpart.h
+++ b/avrdude/avrpart.h
@@ -111,6 +111,7 @@ typedef struct avrpart {
   unsigned char idr;                /* JTAG ICE mkII XML file parameter */
   unsigned char rampz;              /* JTAG ICE mkII XML file parameter */
   unsigned char spmcr;              /* JTAG ICE mkII XML file parameter */
+  unsigned short eecr;              /* JTAC ICE mkII XML file parameter */
 
   OPCODE      * op[AVR_OP_MAX];     /* opcodes */
 
diff --git a/avrdude/config_gram.y b/avrdude/config_gram.y
index f7fe7713..88c65148 100644
--- a/avrdude/config_gram.y
+++ b/avrdude/config_gram.y
@@ -154,6 +154,7 @@ static int parse_cmdbits(OPCODE * op);
 %token K_IDR			/* address of OCD register in IO space */
 %token K_RAMPZ			/* address of RAMPZ reg. in IO space */
 %token K_SPMCR			/* address of SPMC[S]R in memory space */
+%token K_EECR    		/* address of EECR in memory space */
 
 %token TKN_COMMA
 %token TKN_EQUAL
@@ -637,6 +638,12 @@ part_parm :
       free_token($3);
     } |
 
+  K_EECR TKN_EQUAL TKN_NUMBER
+    {
+      current_part->eecr = $3->value.number;
+      free_token($3);
+    } |
+
   K_SERIAL TKN_EQUAL yesno
     {
       if ($3->primary == K_YES)
diff --git a/avrdude/jtagmkII.c b/avrdude/jtagmkII.c
index d3f8d357..79386234 100644
--- a/avrdude/jtagmkII.c
+++ b/avrdude/jtagmkII.c
@@ -71,20 +71,17 @@ 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.
+ * 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)
-static unsigned char hfuse_backup;
-static int internal_hfuse_handling;
+
+/* The length of the device descriptor is firmware-dependent. */
+static size_t device_descriptor_length;
 
 static int jtagmkII_read_byte(PROGRAMMER * pgm, AVRPART * p, AVRMEM * mem,
 			      unsigned long addr, unsigned char * value);
@@ -537,6 +534,7 @@ static int jtagmkII_getsync(PROGRAMMER * pgm) {
 #define MAXTRIES 33
   unsigned char buf[3], *resp, c = 0xff;
   int status;
+  unsigned int fwver;
 
   if (verbose >= 3)
     fprintf(stderr, "%s: jtagmkII_getsync()\n", progname);
@@ -563,6 +561,8 @@ static int jtagmkII_getsync(PROGRAMMER * pgm) {
 
     if (status > 0) {
       if ((c = resp[0]) == RSP_SIGN_ON) {
+	fwver = ((unsigned)resp[8] << 8) | (unsigned)resp[7];
+	memcpy(serno, resp + 10, 6);
 	if (verbose >= 1 && status > 17) {
 	  fprintf(stderr, "JTAG ICE mkII sign-on message:\n");
 	  fprintf(stderr, "Communications protocol version: %u\n",
@@ -581,7 +581,6 @@ static int jtagmkII_getsync(PROGRAMMER * pgm) {
 		  (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]);
@@ -608,6 +607,28 @@ static int jtagmkII_getsync(PROGRAMMER * pgm) {
     return -1;
   }
 
+  device_descriptor_length = sizeof(struct device_descriptor);
+  /*
+   * There's no official documentation from Atmel about what firmware
+   * revision matches what device descriptor length.  The algorithm
+   * below has been found empirically.
+   */
+#define FWVER(maj, min) ((maj << 8) | (min))
+  if (fwver < FWVER(3, 16)) {
+    device_descriptor_length -= 2;
+    fprintf(stderr,
+	    "%s: jtagmkII_getsync(): "
+	    "S_MCU firmware version might be too old to work correctly\n",
+	    progname);
+  } else if (fwver < FWVER(4, 0)) {
+    device_descriptor_length -= 2;
+  }
+#undef FWVER
+  if (verbose >= 2)
+    fprintf(stderr,
+	    "%s: jtagmkII_getsync(): Using a %u-byte device descriptor\n",
+	    progname, device_descriptor_length);
+
   /* Turn the ICE into JTAG mode */
   buf[0] = EMULATOR_MODE_JTAG;
   if (jtagmkII_setparm(pgm, PAR_EMULATOR_MODE, buf) < 0)
@@ -718,6 +739,7 @@ static void jtagmkII_set_devdescr(PROGRAMMER * pgm, AVRPART * p)
   sendbuf.dd.ucSPMCRAddress = p->spmcr;
   sendbuf.dd.ucRAMPZAddress = p->rampz;
   sendbuf.dd.ucIDRAddress = p->idr;
+  u16_to_b2(sendbuf.dd.EECRAddress, p->eecr);
   sendbuf.dd.ucAllowFullPageBitstream =
     (p->flags & AVRPART_ALLOWFULLPAGEBITSTREAM) != 0;
   sendbuf.dd.EnablePageProgramming =
@@ -738,7 +760,8 @@ static void jtagmkII_set_devdescr(PROGRAMMER * pgm, AVRPART * p)
     fprintf(stderr, "%s: jtagmkII_set_devdescr(): "
 	    "Sending set device descriptor command: ",
 	    progname);
-  jtagmkII_send(pgm, (unsigned char *)&sendbuf, sizeof sendbuf);
+  jtagmkII_send(pgm, (unsigned char *)&sendbuf,
+		device_descriptor_length + sizeof(unsigned char));
 
   status = jtagmkII_recv(pgm, &resp);
   if (status <= 0) {
@@ -986,19 +1009,14 @@ static int jtagmkII_initialize(PROGRAMMER * pgm, AVRPART * p)
   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;
+  if (jtagmkII_read_byte(pgm, p, &hfuse, 1, &b) < 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;
+  if ((b & OCDEN) != 0)
+    fprintf(stderr,
+	    "%s: jtagmkII_initialize(): warning: OCDEN fuse not programmed, "
+	    "single-byte EEPROM updates not possible\n",
+	    progname);
 
   return 0;
 }
@@ -1050,46 +1068,10 @@ 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: ",
@@ -1397,10 +1379,6 @@ static int jtagmkII_read_byte(PROGRAMMER * pgm, AVRPART * p, AVRMEM * mem,
   } 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;
@@ -1497,7 +1475,7 @@ static int jtagmkII_write_byte(PROGRAMMER * pgm, AVRPART * p, AVRMEM * mem,
 {
   unsigned char cmd[11];
   unsigned char *resp = NULL, writedata;
-  int status, tries, need_progmode = 1, is_hfuse = 0;
+  int status, tries, need_progmode = 1;
 
   if (verbose >= 2)
     fprintf(stderr, "%s: jtagmkII_write_byte(.., %s, 0x%lx, ...)\n",
@@ -1519,10 +1497,6 @@ static int jtagmkII_write_byte(PROGRAMMER * pgm, AVRPART * p, AVRMEM * mem,
   } 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;
@@ -1583,8 +1557,6 @@ static int jtagmkII_write_byte(PROGRAMMER * pgm, AVRPART * p, AVRMEM * mem,
     goto fail;
   }
 
-  if (is_hfuse && !internal_hfuse_handling)
-    hfuse_backup = data;
   free(resp);
   return 0;
 
diff --git a/avrdude/jtagmkII_private.h b/avrdude/jtagmkII_private.h
index 6558a824..03f80ff9 100644
--- a/avrdude/jtagmkII_private.h
+++ b/avrdude/jtagmkII_private.h
@@ -285,12 +285,6 @@ struct device_descriptor
   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 */
+  /* new as of early 2005, firmware 4.x */
+  unsigned char EECRAddress[2]; /* EECR memory-mapped 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) }
diff --git a/avrdude/lexer.l b/avrdude/lexer.l
index f240a9bd..a8386fc1 100644
--- a/avrdude/lexer.l
+++ b/avrdude/lexer.l
@@ -130,6 +130,7 @@ default_parallel { yylval=NULL; return K_DEFAULT_PARALLEL; }
 default_programmer { yylval=NULL; return K_DEFAULT_PROGRAMMER; }
 default_serial   { yylval=NULL; return K_DEFAULT_SERIAL; }
 devicecode       { yylval=NULL; return K_DEVICECODE; }
+eecr             { yylval=NULL; return K_EECR; }
 eeprom           { yylval=NULL; return K_EEPROM; }
 enablepageprogramming { yylval=NULL; return K_ENABLEPAGEPROGRAMMING; }
 errled           { yylval=NULL; return K_ERRLED; }