This is Colin O'Flynn's mega patch for updating safemode support:

* add support for parts with just 'fuse' memory

    * if any fuse memories are altered, reflect those changes in the
      post-programming safemode check so that safemode no longer
      complains about fuses which were intentionally altered; this
      eliminates the need to completely disable safemode using -u in
      order to program fuses.

    * provide -s option which will not ask to restore fuses, it will
      just do it

Submitted by: Colin O'Flynn <coflynn@newae.com>


git-svn-id: svn://svn.savannah.nongnu.org/avrdude/trunk/avrdude@519 81a1dc3b-b13d-400b-aceb-764788c761c2
This commit is contained in:
bdean 2005-09-21 00:20:32 +00:00
parent 6463d120dc
commit d53e6d7b25
5 changed files with 204 additions and 97 deletions

26
avr.c
View File

@ -33,6 +33,7 @@
#include "lists.h"
#include "pindefs.h"
#include "ppi.h"
#include "safemode.h"
#define DEBUG 0
@ -479,6 +480,30 @@ int avr_write_byte_default(PROGRAMMER * pgm, AVRPART * p, AVRMEM * mem,
int avr_write_byte(PROGRAMMER * pgm, AVRPART * p, AVRMEM * mem,
unsigned long addr, unsigned char data)
{
unsigned char safemode_lfuse;
unsigned char safemode_hfuse;
unsigned char safemode_efuse;
unsigned char safemode_fuse;
/* If we write the fuses, then we need to tell safemode that they *should* change */
safemode_memfuses(0, &safemode_lfuse, &safemode_hfuse, &safemode_efuse, &safemode_fuse);
if (strcmp(mem->desc, "fuse")==0) {
safemode_fuse = data;
}
if (strcmp(mem->desc, "lfuse")==0) {
safemode_lfuse = data;
}
if (strcmp(mem->desc, "hfuse")==0) {
safemode_hfuse = data;
}
if (strcmp(mem->desc, "efuse")==0) {
safemode_efuse = data;
}
safemode_memfuses(1, &safemode_lfuse, &safemode_hfuse, &safemode_efuse, &safemode_fuse);
int rc;
if (pgm->write_byte) {
@ -592,6 +617,7 @@ int avr_write(PROGRAMMER * pgm, AVRPART * p, char * memtype, int size,
pgm->err_led(pgm, ON);
}
}
return i;
}

194
main.c
View File

@ -114,9 +114,9 @@ void usage(void)
" is performed in the order specified.\n"
" -n Do not write anything to the device.\n"
" -V Do not verify.\n"
" -u Disable safemode, you need this option if you\n"
" want to change fuse bits. Otherwise they will be\n"
" recovered if they change\n"
" -u Disable safemode, default when running from a script.\n"
" -s Silent safemode operation, will not ask you if\n"
" fuses should be changed back.\n"
" -t Enter terminal mode.\n"
" -E <exitspec>[,<exitspec>] List programmer exit specifications.\n"
" -y Count # erase cycles in EEPROM.\n"
@ -729,9 +729,13 @@ int main(int argc, char * argv [])
int baudrate; /* override default programmer baud rate */
double bitclock; /* Specify programmer bit clock (JTAG ICE) */
int safemode; /* Enable safemode, 1=safemode on, 0=normal */
int silentsafe; /* Don't ask about fuses, 1=silent, 0=normal */
unsigned char safemode_lfuse = 0xff;
unsigned char safemode_hfuse = 0xff;
unsigned char safemode_efuse = 0xff;
unsigned char safemode_fuse = 0xff;
char * safemode_response;
int fuses_specified = 0;
int fuses_updated = 0;
#if !defined(WIN32NATIVE)
@ -781,7 +785,12 @@ int main(int argc, char * argv [])
set_cycles = -1;
baudrate = 0;
bitclock = 0.0;
safemode = 1; /* Safemode enabled by default */
safemode = 1; /* Safemode on by default */
silentsafe = 0; /* Ask by default */
if (isatty(STDIN_FILENO) == 0)
safemode = 0; /* Turn off safemode if this isn't a terminal */
#if defined(WIN32NATIVE)
@ -826,7 +835,7 @@ int main(int argc, char * argv [])
/*
* process command line arguments
*/
while ((ch = getopt(argc,argv,"?b:c:C:DeE:Fnp:P:qtU:uvVyY:")) != -1) {
while ((ch = getopt(argc,argv,"?b:c:C:DeE:Fnp:P:qtU:suvVyY:")) != -1) {
switch (ch) {
case 'b': /* override default programmer baud rate */
@ -888,6 +897,11 @@ int main(int argc, char * argv [])
quell_progress++ ;
break;
case 's' : /* Silent safemode */
silentsafe = 1;
safemode = 1;
break;
case 't': /* enter terminal mode */
terminal = 1;
break;
@ -1271,17 +1285,11 @@ int main(int argc, char * argv [])
}
if (safemode == 1) {
AVRMEM * m;
/* If safemode is enabled, go ahead and read the current low, high,
and extended fuse bytes as needed */
if (quell_progress < 2) {
fprintf(stderr, "\n");
}
if (safemode_readfuses(&safemode_lfuse, &safemode_hfuse,
&safemode_efuse, pgm, p, verbose) != 0) {
&safemode_efuse, &safemode_fuse, pgm, p, verbose) != 0) {
fprintf(stderr, "%s: safemode: To protect your AVR the programming "
"will be aborted\n",
progname);
@ -1289,36 +1297,8 @@ int main(int argc, char * argv [])
goto main_exit;
}
if (quell_progress < 2) {
fprintf(stderr, "\n");
}
//Save the fuses as default
safemode_memfuses(1, &safemode_lfuse, &safemode_hfuse, &safemode_efuse);
/* Check if user is attempting to write fuse bytes */
for (ln=lfirst(updates); ln; ln=lnext(ln)) {
upd = ldata(ln);
m = avr_locate_mem(p, upd->memtype);
if (m == NULL)
continue;
if (((strcasecmp(m->desc, "lfuse") == 0) ||
(strcasecmp(m->desc, "hfuse") == 0) ||
(strcasecmp(m->desc, "efuse") == 0)) && (upd->op == DEVICE_WRITE)) {
fuses_specified = 1;
fprintf(stderr,
"%s: NOTE: FUSE memory has been specified, and safemode is ON\n"
"%s: This will not allow you to change the fuse bits.\n"
"%s: To disable this feature, specify the -u option.\n",
progname, progname, progname);
}
}
if (quell_progress < 2) {
fprintf(stderr, "\n");
}
safemode_memfuses(1, &safemode_lfuse, &safemode_hfuse, &safemode_efuse, &safemode_fuse);
}
@ -1403,13 +1383,6 @@ int main(int argc, char * argv [])
if (terminal) {
/* Warn user if safemode is on */
if (safemode > 0) {
fprintf(stderr, "%s: safemode is enabled, you will NOT be "
"able to change the fuse bits. Use -u option to disable\n",
progname);
}
/*
* terminal mode
*/
@ -1434,21 +1407,23 @@ int main(int argc, char * argv [])
unsigned char safemodeafter_lfuse = 0xff;
unsigned char safemodeafter_hfuse = 0xff;
unsigned char safemodeafter_efuse = 0xff;
unsigned char safemodeafter_fuse = 0xff;
unsigned char failures = 0;
char yes[1] = {'y'};
if (quell_progress < 2) {
fprintf(stderr, "\n");
}
//Restore the default fuse values
safemode_memfuses(0, &safemode_lfuse, &safemode_hfuse, &safemode_efuse);
safemode_memfuses(0, &safemode_lfuse, &safemode_hfuse, &safemode_efuse, &safemode_fuse);
/* Try reading back fuses, make sure they are reliable to read back */
if (safemode_readfuses(&safemodeafter_lfuse, &safemodeafter_hfuse,
&safemodeafter_efuse, pgm, p, verbose) != 0) {
&safemodeafter_efuse, &safemode_fuse, pgm, p, verbose) != 0) {
/* Uh-oh.. try once more to read back fuses */
if (safemode_readfuses(&safemodeafter_lfuse, &safemodeafter_hfuse,
&safemodeafter_efuse, pgm, p, verbose) != 0) {
&safemodeafter_efuse, &safemodeafter_fuse, pgm, p, verbose) != 0) {
fprintf(stderr,
"%s: safemode: Sorry, reading back fuses was unreliable. "
"I have given up and exited programming mode\n",
@ -1458,55 +1433,110 @@ int main(int argc, char * argv [])
}
}
/* Now check what fuses are against what they should be */
if (safemodeafter_fuse != safemode_fuse) {
fuses_updated = 1;
fprintf(stderr, "%s: safemode: fuse changed! Was %x, and is now %x\n",
progname, safemode_fuse, safemodeafter_fuse);
/* Ask user - should we change them */
if (silentsafe == 0)
safemode_response = terminal_get_input("Would you like this fuse to be changed back? [y/n] ");
else
safemode_response = yes;
if (tolower(safemode_response[0]) == 'y') {
/* Enough chit-chat, time to program some fuses and check them */
if (safemode_writefuse (safemode_fuse, "fuse", pgm, p,
10, verbose) == 0) {
fprintf(stderr, "%s: safemode: and is now rescued\n", progname);
}
else {
fprintf(stderr, "%s: and COULD NOT be changed\n", progname);
failures++;
}
}
}
/* Now check what fuses are against what they should be */
if (safemodeafter_lfuse != safemode_lfuse) {
fuses_updated = 1;
fprintf(stderr, "%s: safemode: lfuse changed! Read as %x, was %x\n",
progname, safemodeafter_lfuse, safemode_lfuse);
fprintf(stderr, "%s: safemode: lfuse changed! Was %x, and is now %x\n",
progname, safemode_lfuse, safemodeafter_lfuse);
/* Enough chit-chat, time to program some fuses and check them */
if (safemode_writefuse (safemode_lfuse, "lfuse", pgm, p,
10, verbose) == 0) {
fprintf(stderr, "%s: safemode: and is now rescued\n", progname);
}
else {
fprintf(stderr, "%s: and COULD NOT be changed\n", progname);
failures++;
/* Ask user - should we change them */
if (silentsafe == 0)
safemode_response = terminal_get_input("Would you like this fuse to be changed back? [y/n] ");
else
safemode_response = yes;
if (tolower(safemode_response[0]) == 'y') {
/* Enough chit-chat, time to program some fuses and check them */
if (safemode_writefuse (safemode_lfuse, "lfuse", pgm, p,
10, verbose) == 0) {
fprintf(stderr, "%s: safemode: and is now rescued\n", progname);
}
else {
fprintf(stderr, "%s: and COULD NOT be changed\n", progname);
failures++;
}
}
}
/* Now check what fuses are against what they should be */
if (safemodeafter_hfuse != safemode_hfuse) {
fuses_updated = 1;
fprintf(stderr, "%s: safemode: hfuse changed! Read as %x, was %x\n",
progname, safemodeafter_hfuse, safemode_hfuse);
fprintf(stderr, "%s: safemode: hfuse changed! Was %x, and is now %x\n",
progname, safemode_hfuse, safemodeafter_hfuse);
/* Enough chit-chat, time to program some fuses and check them */
if (safemode_writefuse(safemode_hfuse, "hfuse", pgm, p,
10, verbose) == 0) {
fprintf(stderr, "%s: safemode: and is now rescued\n", progname);
}
else {
fprintf(stderr, "%s: and COULD NOT be changed\n", progname);
failures++;
/* Ask user - should we change them */
if (silentsafe == 0)
safemode_response = terminal_get_input("Would you like this fuse to be changed back? [y/n] ");
else
safemode_response = yes;
if (tolower(safemode_response[0]) == 'y') {
/* Enough chit-chat, time to program some fuses and check them */
if (safemode_writefuse(safemode_hfuse, "hfuse", pgm, p,
10, verbose) == 0) {
fprintf(stderr, "%s: safemode: and is now rescued\n", progname);
}
else {
fprintf(stderr, "%s: and COULD NOT be changed\n", progname);
failures++;
}
}
}
/* Now check what fuses are against what they should be */
if (safemodeafter_efuse != safemode_efuse) {
fuses_updated = 1;
fprintf(stderr, "%s: safemode: efuse changed! Read as %x, was %x\n",
progname, safemodeafter_efuse, safemode_efuse);
fprintf(stderr, "%s: safemode: efuse changed! Was %x, and is now %x\n",
progname, safemode_efuse, safemodeafter_efuse);
/* Enough chit-chat, time to program some fuses and check them */
if (safemode_writefuse (safemode_efuse, "efuse", pgm, p,
10, verbose) == 0) {
fprintf(stderr, "%s: safemode: and is now rescued\n", progname);
}
else {
fprintf(stderr, "%s: and COULD NOT be changed\n", progname);
failures++;
}
/* Ask user - should we change them */
if (silentsafe == 0)
safemode_response = terminal_get_input("Would you like this fuse to be changed back? [y/n] ");
else
safemode_response = yes;
if (tolower(safemode_response[0]) == 'y') {
/* Enough chit-chat, time to program some fuses and check them */
if (safemode_writefuse (safemode_efuse, "efuse", pgm, p,
10, verbose) == 0) {
fprintf(stderr, "%s: safemode: and is now rescued\n", progname);
}
else {
fprintf(stderr, "%s: and COULD NOT be changed\n", progname);
failures++;
}
}
}
if (quell_progress < 2) {

View File

@ -30,9 +30,13 @@
/* This value from ac_cfg.h */
char * progname = PACKAGE_NAME;
/* Writes the specified fuse in fusename (can be "lfuse", "hfuse", or "efuse") and verifies it. Will try up to tries
amount of times before giving up */
int safemode_writefuse (unsigned char fuse, char * fusename, PROGRAMMER * pgm, AVRPART * p, int tries, int verbose)
/*
* Writes the specified fuse in fusename (can be "lfuse", "hfuse", or
* "efuse") and verifies it. Will try up to tries amount of times
* before giving up
*/
int safemode_writefuse (unsigned char fuse, char * fusename, PROGRAMMER * pgm,
AVRPART * p, int tries, int verbose)
{
AVRMEM * m;
unsigned char fuseread;
@ -50,8 +54,9 @@ int safemode_writefuse (unsigned char fuse, char * fusename, PROGRAMMER * pgm, A
/* Report information to user if needed */
if (verbose > 0) {
fprintf(stderr, "%s: safemode: Wrote %s to %x, read as %x. %d attempts left\n",
progname, fusename, fuse, fuseread, tries-1);
fprintf(stderr,
"%s: safemode: Wrote %s to %x, read as %x. %d attempts left\n",
progname, fusename, fuse, fuseread, tries-1);
}
/* If fuse wrote OK, no need to keep going */
@ -65,8 +70,13 @@ int safemode_writefuse (unsigned char fuse, char * fusename, PROGRAMMER * pgm, A
return returnvalue;
}
/* Reads the fuses three times, checking that all readings are the same. This will ensure that the before values aren't in error! */
int safemode_readfuses (unsigned char * lfuse, unsigned char * hfuse, unsigned char * efuse, PROGRAMMER * pgm, AVRPART * p, int verbose)
/*
* Reads the fuses three times, checking that all readings are the
* same. This will ensure that the before values aren't in error!
*/
int safemode_readfuses (unsigned char * lfuse, unsigned char * hfuse,
unsigned char * efuse, unsigned char * fuse,
PROGRAMMER * pgm, AVRPART * p, int verbose)
{
unsigned char value;
@ -74,11 +84,41 @@ int safemode_readfuses (unsigned char * lfuse, unsigned char * hfuse, unsigned c
unsigned char safemode_lfuse;
unsigned char safemode_hfuse;
unsigned char safemode_efuse;
unsigned char safemode_fuse;
AVRMEM * m;
safemode_lfuse = *lfuse;
safemode_hfuse = *hfuse;
safemode_efuse = *efuse;
safemode_fuse = *fuse;
/* Read fuse three times */
fusegood = 2; /* If AVR device doesn't support this fuse, don't want
to generate a verify error */
m = avr_locate_mem(p, "fuse");
if (m != NULL) {
fusegood = 0; /* By default fuse is a failure */
avr_read_byte(pgm, p, m, 0, &safemode_fuse);
avr_read_byte(pgm, p, m, 0, &value);
if (value == safemode_fuse) {
avr_read_byte(pgm, p, m, 0, &value);
if (value == safemode_fuse){
fusegood = 1; /* Fuse read OK three times */
}
}
}
if (fusegood == 0) {
fprintf(stderr,
"%s: safemode: Verify error - unable to read fuse properly. "
"Programmer may not be reliable.\n", progname);
return -1;
}
else if ((fusegood == 1) && (verbose > 0)) {
printf("%s: safemode: fuse reads as %X\n", progname, safemode_fuse);
}
/* Read lfuse three times */
fusegood = 2; /* If AVR device doesn't support this fuse, don't want
@ -161,20 +201,28 @@ int safemode_readfuses (unsigned char * lfuse, unsigned char * hfuse, unsigned c
*lfuse = safemode_lfuse;
*hfuse = safemode_hfuse;
*efuse = safemode_efuse;
*fuse = safemode_fuse;
return 0;
}
/* This routine will store the current values pointed to by lfuse, hfuse, and efuse into an internal buffer in this routine
when save is set to 1. When save is 0 (or not 1 really) it will copy the values from the internal buffer into the locations
pointed to be lfuse, hfuse, and efuse. This allows you to change the fuse bits if needed from another routine (ie: have it so
if user requests fuse bits are changed, the requested value is now verified */
int safemode_memfuses (int save, unsigned char * lfuse, unsigned char * hfuse, unsigned char * efuse)
/*
* This routine will store the current values pointed to by lfuse,
* hfuse, and efuse into an internal buffer in this routine when save
* is set to 1. When save is 0 (or not 1 really) it will copy the
* values from the internal buffer into the locations pointed to be
* lfuse, hfuse, and efuse. This allows you to change the fuse bits if
* needed from another routine (ie: have it so if user requests fuse
* bits are changed, the requested value is now verified
*/
int safemode_memfuses (int save, unsigned char * lfuse, unsigned char * hfuse,
unsigned char * efuse, unsigned char * fuse)
{
static unsigned char safemode_lfuse = 0xff;
static unsigned char safemode_hfuse = 0xff;
static unsigned char safemode_efuse = 0xff;
static unsigned char safemode_fuse = 0xff;
switch (save) {
@ -183,6 +231,7 @@ int safemode_memfuses (int save, unsigned char * lfuse, unsigned char * hfuse, u
safemode_lfuse = *lfuse;
safemode_hfuse = *hfuse;
safemode_efuse = *efuse;
safemode_fuse = *fuse;
break;
/* Read back the fuses */
@ -190,6 +239,7 @@ int safemode_memfuses (int save, unsigned char * lfuse, unsigned char * hfuse, u
*lfuse = safemode_lfuse;
*hfuse = safemode_hfuse;
*efuse = safemode_efuse;
*fuse = safemode_fuse;
break;
}

View File

@ -28,12 +28,12 @@ amount of times before giving up */
int safemode_writefuse (unsigned char fuse, char * fusename, PROGRAMMER * pgm, AVRPART * p, int tries, int verbose);
/* Reads the fuses three times, checking that all readings are the same. This will ensure that the before values aren't in error! */
int safemode_readfuses (unsigned char * lfuse, unsigned char * hfuse, unsigned char * efuse, PROGRAMMER * pgm, AVRPART * p, int verbose);
int safemode_readfuses (unsigned char * lfuse, unsigned char * hfuse, unsigned char * efuse, unsigned char * fuse, PROGRAMMER * pgm, AVRPART * p, int verbose);
/* This routine will store the current values pointed to by lfuse, hfuse, and efuse into an internal buffer in this routine
when save is set to 1. When save is 0 (or not 1 really) it will copy the values from the internal buffer into the locations
pointed to be lfuse, hfuse, and efuse. This allows you to change the fuse bits if needed from another routine (ie: have it so
if user requests fuse bits are changed, the requested value is now verified */
int safemode_memfuses (int save, unsigned char * lfuse, unsigned char * hfuse, unsigned char * efuse);
int safemode_memfuses (int save, unsigned char * lfuse, unsigned char * hfuse, unsigned char * efuse, unsigned char * fuse);
#endif //__safemode_h

1
term.h
View File

@ -26,5 +26,6 @@
#include "pgm.h"
int terminal_mode(PROGRAMMER * pgm, struct avrpart * p);
char * terminal_get_input(const char *prompt);
#endif