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:
parent
c5cfb14c31
commit
27e53d7aac
149
avrdude/main.c
149
avrdude/main.c
|
@ -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);
|
||||||
|
|
Loading…
Reference in New Issue