Add Safe Mode. Fuse settings will be restored at the end of a programming session unless the -u switch is specified.

git-svn-id: svn://svn.savannah.nongnu.org/avrdude/trunk@440 81a1dc3b-b13d-400b-aceb-764788c761c2
This commit is contained in:
Eric Weddington 2005-01-24 21:26:11 +00:00
parent c5cfb14c31
commit 27e53d7aac
1 changed files with 149 additions and 2 deletions

View File

@ -51,6 +51,7 @@
#include "par.h" #include "par.h"
#include "pindefs.h" #include "pindefs.h"
#include "term.h" #include "term.h"
#include "safemode.h"
enum { enum {
@ -109,6 +110,9 @@ void usage(void)
" is performed in the order specified.\n" " is performed in the order specified.\n"
" -n Do not write anything to the device.\n" " -n Do not write anything to the device.\n"
" -V Do not verify.\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"
" -t Enter terminal mode.\n" " -t Enter terminal mode.\n"
" -E <exitspec>[,<exitspec>] List programmer exit specifications.\n" " -E <exitspec>[,<exitspec>] List programmer exit specifications.\n"
" -v Verbose output. -v -v for more.\n" " -v Verbose output. -v -v for more.\n"
@ -661,6 +665,7 @@ int do_op(PROGRAMMER * pgm, struct avrpart * p, UPDATE * upd, int nowrite,
return 0; return 0;
} }
/* /*
* main routine * main routine
*/ */
@ -699,6 +704,7 @@ int main(int argc, char * argv [])
char * e; /* for strtol() error checking */ char * e; /* for strtol() error checking */
int quell_progress; int quell_progress;
int baudrate; /* override default programmer baud rate */ int baudrate; /* override default programmer baud rate */
int safemode; /* Enable safemode, 1=safemode on, 0=normal */
#if !defined(WIN32NATIVE) #if !defined(WIN32NATIVE)
char * homedir; char * homedir;
#endif #endif
@ -745,6 +751,7 @@ int main(int argc, char * argv [])
do_cycles = 0; do_cycles = 0;
set_cycles = -1; set_cycles = -1;
baudrate = 0; baudrate = 0;
safemode = 1; /* Safemode enabled by default */
#if defined(WIN32NATIVE) #if defined(WIN32NATIVE)
@ -789,7 +796,7 @@ int main(int argc, char * argv [])
/* /*
* process command line arguments * process command line arguments
*/ */
while ((ch = getopt(argc,argv,"?b:c:C:DeE:Fnp:P:qtU:vVyY:")) != -1) { while ((ch = getopt(argc,argv,"?b:c:C:DeE:Fnp:P:qtU:uvVyY:")) != -1) {
switch (ch) { switch (ch) {
case 'b': /* override default programmer baud rate */ case 'b': /* override default programmer baud rate */
@ -846,6 +853,10 @@ int main(int argc, char * argv [])
terminal = 1; terminal = 1;
break; break;
case 'u' : /* Disable safemode */
safemode = 0;
break;
case 'U': case 'U':
upd = parse_op(optarg); upd = parse_op(optarg);
if (upd == NULL) { if (upd == NULL) {
@ -1200,6 +1211,53 @@ int main(int argc, char * argv [])
} }
} }
unsigned char safemode_lfuse = 0xff;
unsigned char safemode_hfuse = 0xff;
unsigned char safemode_efuse = 0xff;
if (safemode == 1) {
/* If safemode is enabled, go ahead and read the current low, high, and extended fuse bytes as needed */
fprintf(stderr, "\n");
if (safemode_readfuses (&safemode_lfuse, &safemode_hfuse, &safemode_efuse, pgm, p, verbose) != 0) {
fprintf(stderr, "%s: safemode: To protect your AVR the programming will be aborted\n", progname);
exitrc = 1;
goto main_exit;
}
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 */
AVRMEM * m;
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)) {
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);
}
}
fprintf(stderr, "\n");
}
if ((erase == 0) && (auto_erase == 1)) { if ((erase == 0) && (auto_erase == 1)) {
AVRMEM * m; AVRMEM * m;
@ -1271,6 +1329,13 @@ int main(int argc, char * argv [])
if (terminal) { 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 * terminal mode
*/ */
@ -1287,12 +1352,94 @@ int main(int argc, char * argv [])
} }
} }
/* Right before we exit programming mode, which will make the fuse bits active,
check to make sure they are still correct */
if (safemode == 1){
/* If safemode is enabled, go ahead and read the current low, high, and extended fuse bytes as needed */
unsigned char safemodeafter_lfuse = 0xff;
unsigned char safemodeafter_hfuse = 0xff;
unsigned char safemodeafter_efuse = 0xff;
unsigned char failures = 0;
fprintf(stderr, "\n");
//Restore the default fuse values
safemode_memfuses(0, &safemode_lfuse, &safemode_hfuse, &safemode_efuse);
/* 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) {
/* Uh-oh.. try once more to read back fuses */
if (safemode_readfuses (&safemodeafter_lfuse, &safemodeafter_hfuse, &safemodeafter_efuse, pgm, p, verbose) != 0) {
fprintf(stderr, "%s: safemode: Sorry, reading back fuses was unreliable. I have given up and exited programming mode\n",
progname);
exitrc = 1;
goto main_exit;
}
}
/* Now check what fuses are against what they should be */
if (safemodeafter_lfuse != safemode_lfuse) {
fprintf(stderr, "%s: safemode: lfuse changed! Read as %x, was %x\n", progname,
safemodeafter_lfuse, safemode_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++;
}
}
/* Now check what fuses are against what they should be */
if (safemodeafter_hfuse != safemode_hfuse) {
fprintf(stderr, "%s: safemode: hfuse changed! Read as %x, was %x\n", progname,
safemodeafter_hfuse, safemode_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++;
}
}
/* Now check what fuses are against what they should be */
if (safemodeafter_efuse != safemode_efuse) {
fprintf(stderr, "%s: safemode: efuse changed! Read as %x, was %x\n", progname,
safemodeafter_efuse, safemode_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++;
}
}
fprintf(stderr, "%s: safemode: ", progname);
if (failures == 0) {
fprintf(stderr, "Fuses OK\n");
}
else {
fprintf(stderr, "Fuses not recovered, sorry\n");
}
}
main_exit: main_exit:
/* /*
* program complete * program complete
*/ */
pgm->powerdown(pgm); pgm->powerdown(pgm);
pgm->disable(pgm); pgm->disable(pgm);