diff --git a/avrdude/avr.c b/avrdude/avr.c index e48a5ff0..17b27741 100644 --- a/avrdude/avr.c +++ b/avrdude/avr.c @@ -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; } diff --git a/avrdude/main.c b/avrdude/main.c index 0eabd256..98dcd5fa 100644 --- a/avrdude/main.c +++ b/avrdude/main.c @@ -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 [,] 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 */ @@ -1433,22 +1406,24 @@ int main(int argc, char * argv []) * high, and extended fuse bytes as needed */ unsigned char safemodeafter_lfuse = 0xff; unsigned char safemodeafter_hfuse = 0xff; - unsigned char safemodeafter_efuse = 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", @@ -1457,56 +1432,111 @@ int main(int argc, char * argv []) goto main_exit; } } + + /* 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); + + /* 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++; + /* 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) { diff --git a/avrdude/safemode.c b/avrdude/safemode.c index 5a20178b..d71500ba 100644 --- a/avrdude/safemode.c +++ b/avrdude/safemode.c @@ -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; } diff --git a/avrdude/safemode.h b/avrdude/safemode.h index 7e5c4d83..5c1792bc 100644 --- a/avrdude/safemode.h +++ b/avrdude/safemode.h @@ -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 diff --git a/avrdude/term.h b/avrdude/term.h index ca96db0a..e88ab0aa 100644 --- a/avrdude/term.h +++ b/avrdude/term.h @@ -26,5 +26,6 @@ #include "pgm.h" int terminal_mode(PROGRAMMER * pgm, struct avrpart * p); +char * terminal_get_input(const char *prompt); #endif