/* SP12: A serial programmer for working with Atmel AVR uCs */ /* Copyright (C) 1997-2008 Ken Huntington, Kevin Towers, */ /* Artur Pundsack, Pitronics. */ /* This program is free software; you can redistribute it and/or */ /* modify it under the terms of the GNU General Public License */ /* as published by the Free Software Foundation; either version 2 */ /* of the License, or (at your option) any later version. */ /* This program is distributed in the hope that it will be useful, */ /* but WITHOUT ANY WARRANTY; without even the implied warranty of */ /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */ /* GNU General Public License for more details. */ /* You should have received a copy of the GNU General Public License */ /* along with this program; if not, write to the Free Software */ /* Foundation, Inc., 59 Temple Place - Suite 330, Boston, */ /* MA 02111-1307, USA. */ /* Pitronics can be reached by email: sbolt@xs4all.nl */ /* Kevin Towers can be reached by email: ktowers@omnexcontrols.com */ /* Ken Huntington can be reached by email: kenh@compmore.net */ /* Artur Pundsack can be reached by email: ap@pa-tec.de */ #if defined(__OpenBSD__) #include #include #endif #include #include #include #include "dos_cpt.h" #include #include "sp12.h" #define VERSION "2.1.1" const char USAGE[] = { " SP12/32 version %s: A serial programmer for Atmel AVR uCs.\n" " Copyright (C) 1997-2008 Ken Huntington, Kevin Towers,\n" " Artur Pundsack, Pitronics.\n" "SYNOPSIS\n" " sp12 {-options} [filename or address(:data)] {-options} [filename...\n" "OPTIONS\n" " i[nnn] - init E - chip erase\n" " e - eprom area B - blank check\n" " p - program area C - calculate checksum\n" " w - write to L[n...n] - lock fuses\n" " r - read from F[n...n] - fuses\n" " a - address(:data) next H[n...n] - high fuses\n" " f - filename next X[n...n] - extended fuses\n" " I - create Intel Hex file c[nn] - calibration byte(s)\n" " h - hex dump with ascii M - match Sck to uC clock\n" " o0, o1 - optimization P - parallel port control\n" " s - show supported uCs t - timing check\n" "EXAMPLES\n" " sp12 -M4 -wF10011 -wpfC prog.hex -wefC eep.hex -wL00 (sets timing \n" " for 4MHz, sets fuses, then writes prog.hex into the program area\n" " and eep.hex into the eeprom, providing checksums for both; and\n" " finally a read/write lock is set)\n" " sp12 -rF -rH -rL -rc (reads fuses, locks and calibration if possible)\n" " sp12 -wea 0x01:0x99 (Writes 0x99 into eeprom address 0x01)\n\n"}; static int initFlag = 0; /* i on command line; flag set nn */ static int flashFlag = 0; /* p on command line */ static int eepromFlag = 0; /* e */ static int writeFlag = 0; /* w */ static int readFlag = 0; /* r */ static int lockFlag = 0; /* L */ static int fusesFlag = 0; /* F */ static int highFFlag = 0; /* H */ static int extdFFlag = 0; /* X */ static int calibFlag = 0; /* c */ static unsigned long calibAddress = 0; static int fileFlag = 0; /* d */ static int addressFlag = 0; /* a */ static int eraseFlag = 0; /* E */ static int blankChkFlag = 0; /* B */ static int checksumFlag = 0; /* C */ static int testFlag = 0; /* T */ static int portFlag = 0; /* P */ static int optimizeFlag = 0; /* o, 0, 1 */ static int overlayFlag = 0; /* O */ static float clkSpeed = 0; /* M, value between 0.1 and 12 */ static float prevClkSpeed = 0; /* previous clkSpeed */ static int IntelFlag = 0; /* I */ static int hexAsciiFlag = 0; /* h */ static int addressAvailable = 0; static int pathAvailable = 0; static char flashPath[MAXLEN]; /* path/filename source or destination */ static char eepromPath[MAXLEN]; /* path/filename source or destination */ static char checksumPath[MAXLEN]; /* path/filename source */ static char commandStr[MAXLEN]; /* stores commands for logging */ static char fusesBits[MAXLEN] = ""; static char lockBits[MAXLEN] = ""; static char calibByte[MAXLEN] = ""; static char identifier[MAXLEN] = ""; static unsigned int flashAddress = 0; static unsigned int flashData = 0; static unsigned int eepromAddress = 0; static unsigned int eepromData = 0; static unsigned int *flashBuf; /* flash buffer */ static unsigned int *eepromBuf; /* eeprom buffer */ static clock_t sp12Start, sp12End; static double sp12Elapsed; void exitSp12(int exitState) { char binary[9] = "76543210"; /* Stores conversion num to binary */ portControl(DEFAULT_EXIT_STATE, 1); num2bin((unsigned char) DEFAULT_EXIT_STATE, binary); printf("Writing %#04x (%d, B%s) ", DEFAULT_EXIT_STATE, DEFAULT_EXIT_STATE, binary); printf("to the parallel port data bits.\n"); sp12End = clock(); sp12Elapsed = ((double) (sp12End - sp12Start)) / CLOCKS_PER_SEC; printf("Sp12 was active for %#3.2f seconds.\n", sp12Elapsed); free(flashBuf); free(eepromBuf); exit(exitState); } /* Merely check whether options -L, -E, -F, -R, -S, -K, D, V, */ /* A or U was used, and say something about it. */ void reportLEFHXcFlag(void) { if (lockFlag) { printf("You have selected option -L to read or write lock fuses,\n"); printf("which has had no effect. Use this option only in combination\n "); printf("with -r and -w, like -rL or -wL00\n"); lockFlag = 0; } if (eraseFlag) { printf("You have selected option -E for erase, which has had no\n"); printf("effect. Options -w, -p and -f together cause an automatic\n"); printf("erase; -E should be used on its own or together with B if\n"); printf("you want a blank check afterwards.\n"); eraseFlag = 0; } if (fusesFlag) { printf("You have selected option -F to read or write fuse bits,\n"); printf("which has had no effect. This option can only be used in\n"); printf("the commands -rF and -wF.\n"); fusesFlag = 0; } if (highFFlag) { printf("You have selected option -H to read or write fuse bits,\n"); printf("which has had no effect. This option can only be used in\n"); printf("the commands -rH and -wH.\n"); highFFlag = 0; } if (extdFFlag) { printf("You have selected option -X to read or write extended fuses,\n"); printf("which has had no effect. This option can only be used in\n"); printf("the commands -rX and -wX.\n"); extdFFlag = 0; } if (calibFlag) { printf("You have selected option -c to read the calibration byte,\n"); printf("which has had no effect. This option can only be used in\n"); printf("the command -rc.\n"); calibFlag = 0; } } /* Merely check whether option -B was used, */ /* and say something about it. */ void reportBflag(void) { if (blankChkFlag) { printf("You have selected option -B for blank check, which has had \n"); printf("no effect. Options -w, -p and -f together cause an automatic\n"); printf("erase; if you also want a blank check before programming,\n"); printf("use -Bwpf. Use -EB if you just want an erase followed by a\n"); printf("blank check, or -B on its own for a blank check without a\n"); printf("preceding erase.\n"); blankChkFlag = 0; } } /* Blank check the device. */ int blank_check(void) { int signal = 0; printf("Performing blank check...\n"); signal = blankCheck(device.flashLimit, device.eepromLimit); if (signal == 0) printf("The program and eeprom area's are blank.\n"); if ((signal & 0x01) == 1) printf("The program area is NOT blank.\n"); if ((signal & 0x02) == 2) printf("The eeprom area is NOT blank.\n"); return(signal); } /* The command processor */ void processCommand(void) { unsigned long command; long address; int error; /* Storing return value */ int deviceCode = 0; char binary[9] = "76543210"; /* Stores conversion num to binary */ int rFlag = 0; int idx = 0; /* * If it hasn't been done yet, then set the device parameters * according to device code and option -i[NN] */ if (!device.initPerformed) { printf("Enabling AVR serial reading/programming...\n"); /* * First see if it's a 1200, which doesn't echo 0x53 * on the third byte of PROGRAM_ENABLE. * Initiating contact at low speed */ strlcpy(device.name, "AT90S1200(A)", sizeof(device.name)); setSckTiming(0.1); enableSPI(1200); deviceCode = setDevicePars(initFlag, identifier); if (deviceCode == 1) { fprintf(stderr, "_sp12dev not found\n"); exitSp12(2); } if (deviceCode == 2) { fprintf(stderr, "_sp12dev corrupt.\n"); exitSp12(2); } if (deviceCode == 3) { /* * It doesn't look like a 1200. If a uC is connected, * the SPI shiftregister is not in synch. We'll now fail * if it is an out of synch 1200, but other uCs do * echo 0x53 on the third byte of PROGRAM_ENABLE. * So we'll try synch pulses for a while. */ enableSPI(0); deviceCode = setDevicePars(initFlag, identifier); if (deviceCode == 1) { fprintf(stderr, "_sp12dev not found\n"); exitSp12(2); } if (deviceCode == 2) { fprintf(stderr, "_sp12dev corrupt.\n"); exitSp12(2); } if (device.sigByte_0 == 0 && device.sigByte_1 == 1 && device.sigByte_2 == 2) { printf("WARNING: You have connected an unidentifiable\n"); printf(" device, which may be locked mode 3. \n"); printf(" Access to a supported, mode 3 locked \n"); printf(" device can be regained, but only by \n"); printf(" erasing it first.\n"); printf(" Check SP12.doc for details.\n\n"); } } if (initFlag == 0) { printf("The device code bytes 0,1,2: %#x, %#x, %#x were read\n", device.sigByte_0, device.sigByte_1, device.sigByte_2); printf("from parallel port %#x and indicate the following:\n", portAddress); printf("You have connected an %s\n", device.name); printf("The device was made by %s\n\n", device.madeBy); } if (device.flashLimit == 0 || device.eepromLimit == 0) { printf("Nothing to do for sp12.\n"); exitSp12(1); } if (initFlag != 0 && device.flashLimit != 0) { printf("Device code check OVERRULED! Assuming an %s\n\n", device.name); } /* * Continue with the Sck wave form for the now known uC, * at the default speed. */ setSckTiming(clockSpdDefault); } /* * Do a few command sanity checks */ error = flashFlag + eepromFlag + writeFlag + readFlag + lockFlag \ + fusesFlag + highFFlag + extdFFlag + calibFlag + fileFlag \ + addressFlag + eraseFlag + blankChkFlag + checksumFlag + testFlag \ + portFlag + optimizeFlag + overlayFlag; if (((fusesFlag || highFFlag || extdFFlag || lockFlag || calibFlag) \ && error > 2) || (!readFlag && !writeFlag)) { if (fusesFlag) { printf("Use F only in the commands -rF or -wF\n"); exitSp12(2); } if (highFFlag) { printf("Use H only in the commands -rH or -wH\n"); exitSp12(2); } if (extdFFlag) { printf("Use X only in the commands -rX or -wX\n"); exitSp12(2); } if (lockFlag) { printf("Use L only in the commands -rL or -wL\n"); exitSp12(2); } if (calibFlag) { printf("Use c only in the command -rc[n]\n"); exitSp12(2); } } if (flashFlag && eepromFlag) { printf("Do not use options -p and -e in a single command.\n"); exitSp12(2); } if (checksumFlag && !eepromFlag && !flashFlag) { printf("Use C only in commands like -Ce, -Cp, -Cef \n"); exitSp12(2); } /* * Inititalize buffers */ for (address = 0; address < device.flashLimit; address++) flashBuf[address] = 0xFFFF; for (address = 0; address < device.eepromLimit; address++) eepromBuf[address] = 0xFFF; /* * Set Sck timing to match the now known uC's wave form * and clock speed asked for by an -Mn.n command. */ if (clkSpeed && clkSpeed != prevClkSpeed) { printf("Sck timing set for %.1f MHz or higher.\n", setSckTiming(clkSpeed)); prevClkSpeed = clkSpeed; } clkSpeed = 0; /* * if r --> p || e || F || L * rp --> rpf --> read program area; write to file * rpa --> read program address to stdout * rp --> read program area to stdout * re --> ref --> read eeprom area; write to file * rea --> read eeprom address to stdout * re --> read eeprom area to stdout * rF --> read the fuse bits, if possible * rL --> read the lock bits, if possible * check for C * check for E, B, R, S, but just report them */ if (readFlag && writeFlag) { printf("Do not use options -w and -r in a single command.\n"); exitSp12(2); } if (readFlag) { readFlag = 0; if ((!pathAvailable || addressAvailable) && IntelFlag) { printf("The Intel hex format is only available when writing\n"); printf("an entire memory area to file.\n"); exitSp12(2); } if (addressAvailable && hexAsciiFlag) { printf("A hex dump with ascii translation is only possible\n"); printf("when writing an entire memory area to file.\n"); exitSp12(2); } if (IntelFlag && hexAsciiFlag) { printf("Select either (I)ntel hex format or (h)ex dump with\n"); printf("ascii translation; not both at the same time\n"); exitSp12(2); } if (flashFlag) { flashFlag = 0; if (addressAvailable) { addressAvailable = 0; flashData = readCodeWord(flashAddress); printf("The word %#06x was read from program address %#08x\n", flashData, flashAddress); } else { printf("Reading program area.\n"); readFlashArea(flashBuf, device.flashLimit); if (pathAvailable) { pathAvailable = 0; printf("Writing program area content to %s\n", flashPath); if (fileFlashBuf(flashBuf, device.flashLimit, flashPath, IntelFlag, hexAsciiFlag) != 0) { printf("%s %s\n", FILE_WRITE_ERROR, flashPath); exitSp12(2); } IntelFlag = 0; hexAsciiFlag = 0; } else { if (hexAsciiFlag) { printBuffer(flashBuf, device.flashLimit, 1); hexAsciiFlag = 0; } else { for (address = 0; address < device.flashLimit; address++) printf("%06lx:%04x\n", address, flashBuf[address]); } } } if (checksumFlag) { checksumFlag = 0; readFlashArea(flashBuf, device.flashLimit); printf("Checksum program area: %04x\n", checksum(flashBuf, device.flashLimit)); } } if (eepromFlag) { eepromFlag = 0; if (addressAvailable) { addressAvailable = 0; eepromData = readDataByte(eepromAddress); num2bin((unsigned char) eepromData, binary); printf("The byte %#04x (%d, %#o, B%s) ", eepromData, eepromData, eepromData, binary); printf("was read from eeprom address %#06x\n", eepromAddress); } else { printf("Reading eeprom area.\n"); readEepromArea(eepromBuf, device.eepromLimit); if (pathAvailable) { pathAvailable = 0; printf("Writing eeprom area content to %s\n", eepromPath); if (fileEepromBuf(eepromBuf, device.eepromLimit, eepromPath, IntelFlag, hexAsciiFlag) != 0) { printf("%s %s\n", FILE_WRITE_ERROR, eepromPath); exitSp12(2); } IntelFlag = 0; hexAsciiFlag = 0; } else { if (hexAsciiFlag) { printBuffer(eepromBuf, device.eepromLimit, 0); hexAsciiFlag = 0; } else { printf("Address: Data in hex, dec, oct, bin\n"); for (address = 0; address < device.eepromLimit; address++) { num2bin((unsigned char) eepromBuf[address], binary); printf( " %#04lx: %#04x %3d %#4o %s\n", address, eepromBuf[address], eepromBuf[address], eepromBuf[address], binary); } } } } if (checksumFlag) { checksumFlag = 0; readEepromArea(eepromBuf, device.eepromLimit); printf("Checksum eeprom area: %04x\n", checksum(eepromBuf, device.eepromLimit)); } } if (fusesFlag) { fusesFlag = 0; rFlag = readFuses(READ_FUSES, fusesBits, R_FUSESLSB, R_FUSESLEN); if (rFlag == 9) { fprintf(stderr, "For the %s: Read_fuses not defined in _sp12dev.\n", device.name); } else { printf("%s are the fuse bits read from an %s\n", fusesBits, device.name); printf("%s\n", FUSES_MESSAGE); } } if (highFFlag) { highFFlag = 0; rFlag = readFuses(READ_HIGH_FUSES, fusesBits, RH_FUSESLSB, RH_FUSESLEN); if (rFlag == 9) { fprintf(stderr, "For the %s: Read_high_fuses not defined in _sp12dev.\n", device.name); } else { printf("%s are the high fuse bits read from an %s\n", fusesBits, device.name); printf("%s\n", H_FUSES_MESSAGE); } } if (extdFFlag) { extdFFlag = 0; rFlag = readFuses(READ_EXTD_FUSES, fusesBits, RX_FUSESLSB, RX_FUSESLEN); if (rFlag == 9) { fprintf(stderr, "For the %s: Read_extd_fuses not defined in _sp12dev.\n", device.name); } else { printf("%s are the extended fuse bits read from an %s\n", fusesBits, device.name); printf("%s\n", X_FUSES_MESSAGE); } } if (lockFlag) { lockFlag = 0; rFlag = readFuses(READ_LOCK, lockBits, R_LOCKLSB, R_LOCKLEN); if (rFlag == 9) { fprintf(stderr, "For the %s: Read_locks not defined in _sp12dev.\n", device.name); } else { printf("%s are the lock bits read from an %s\n", lockBits, device.name); printf("%s\n", LOCK_MESSAGE); } } if (calibFlag) { calibFlag = 0; command = READ_CALIBRATION | (calibAddress << 8); rFlag = readFuses(command, calibByte, CALIBLSB, CALIBLEN); if (rFlag == 9) { fprintf(stderr, "For the %s: Read_calibration not defined in _sp12dev.\n", device.name); } else { printf("0x%02lx is the calibration byte read from address 0x%02lx\n", strtol(calibByte, NULL, 2), calibAddress); printf("%s\n", CALIB_MESSAGE); } } reportLEFHXcFlag(); reportBflag(); } /* * If w --> p || e * wp --> f || a * wpf --> chip erase; * write file to program area * wpa --> NO chip erase (warning); * write address:data * we --> f || a * wef --> write file to eeprom area * wpa --> write address:data * wF --> write the fuse bits, if possible * wL --> write the lock bits, if possible * check for C; complete write before reading p || e * back into array to compute the checksum * check for E, R, S but just report them */ if (writeFlag) { writeFlag = 0; timeConst.byteWrite = timeConst.byteWriteDefault; timeConst.byteWriteAdjusted = 0; timeConst.pageWrite = timeConst.pageWriteDefault; timeConst.pageWriteAdjusted = 0; writeRetries = 0; if (flashFlag) { flashFlag = 0; if (addressAvailable) { addressAvailable = 0; if (device.pageMode) { printf ("ERROR: Single address flash programming " "not available in page mode.\n"); exitSp12(2); } printf("WARNING: writing to single address in program area.\n"); printf(" Chip erase is not automatic; unless you \n"); printf(" used a separate -E command, it may not be \n"); printf(" possible to correctly write new data.\n"); printf("Writing %#06x into address %#08x in program area.\n", flashData, flashAddress); error = writeFlashVerified(flashAddress, flashData, optimizeFlag); if (logWrites(commandStr, flashAddress, flashData, flashPath, flashBuf, overlayFlag, &error) != 0) printf("%s %s\n", FILE_WRITE_ERROR, "sp12log.txt"); if (error) { printf("Readback ERROR at program address %#06x\n", flashAddress); exitSp12(3); } } else if (pathAvailable) { /* Write file to flash ////////////*/ pathAvailable = 0; if (!overlayFlag) { printf("Performing chip erase...\n"); eraseDevice(); } if (blankChkFlag) { blankChkFlag = 0; if(blank_check()) exitSp12(3); } /* Read the HEX file */ printf("Writing content of %s into program area.\n", flashPath); error = readFlashFile(flashPath, flashBuf, device.flashLimit); if (error) { printf("%s %s\n", flashPath, FILE_ERROR); exitSp12(2); } /* Now copy file to flash */ error = writeFlashArea(flashBuf, device.flashLimit, optimizeFlag); if (logWrites(commandStr, flashAddress, flashData, flashPath, flashBuf, overlayFlag, &error) != 0) printf("%s %s\n", FILE_WRITE_ERROR, "sp12log.txt"); if (error) { printf("Readback ERROR after %d write retries.\n", writeRetries); if (overlayFlag) printf("The error may be due to an overlay conflict.\n"); exitSp12(3); } else { printf("%s written and verified.\n", flashPath); printf("write retries: %d\n", writeRetries); } } /* Up to here the file to flash functions///////////////////*/ if (checksumFlag) { checksumFlag = 0; readFlashArea(flashBuf, device.flashLimit); printf("Checksum program area: %04x\n", checksum(flashBuf, device.flashLimit)); } } if (eepromFlag) { eepromFlag = 0; if (addressAvailable) { addressAvailable = 0; printf("Writing %#x into address %#x in eeprom area.\n", eepromData, eepromAddress); error=writeEepromVerified(eepromAddress, eepromData, optimizeFlag); if (logWrites(commandStr, eepromAddress, eepromData, eepromPath, eepromBuf, overlayFlag, &error) != 0) printf("%s %s\n", FILE_WRITE_ERROR, "sp12log.txt"); if (error) { printf("Readback ERROR at eeprom address %#04x\n", eepromAddress); exitSp12(3); } } else if (pathAvailable) { pathAvailable = 0; printf("Writing content of %s into eeprom area.\n", eepromPath); error = readEepromFile(eepromPath, eepromBuf, device.eepromLimit); if (error) { printf("%s %s\n", eepromPath, FILE_ERROR); exitSp12(2); } error = writeEepromArea(eepromBuf, device.eepromLimit, optimizeFlag, overlayFlag); if (logWrites(commandStr, eepromAddress, eepromData, eepromPath, eepromBuf, overlayFlag, &error) != 0) printf("%s %s\n", FILE_WRITE_ERROR, "sp12log.txt"); if (error) { printf("Readback ERROR after %d write retries.\n", writeRetries); exitSp12(3); } else { printf("%s written and verified.\n", eepromPath); printf("write retries: %d, byteWrite: %ld percent of default\n", writeRetries, (timeConst.byteWrite * 100) / timeConst.byteWriteDefault); } } if (checksumFlag) { checksumFlag = 0; readEepromArea(eepromBuf, device.eepromLimit); printf("Checksum eeprom area: %04x\n", checksum(eepromBuf, device.eepromLimit)); } reportBflag(); } if (lockFlag) { lockFlag = 0; logLocks(flashBuf, lockBits); rFlag = writeFuses(WRITE_LOCK_HM, WRITE_LOCK_LM, lockBits, \ W_LOCKLSB, W_LOCKLEN); if (rFlag == 9) { fprintf(stderr, "For the %s: Write_lock not defined in _sp12dev.\n", device.name); } else if (rFlag == 2) { fprintf(stderr, "For the %s: Wrong number of lock bits, expect %d.\n", device.name, W_LOCKLEN); } else { for (idx = 0; idx < R_LOCKLEN - W_LOCKLEN; idx++) printf(" "); printf("%s are the lock bits written into an %s\n%s\n", lockBits, device.name, LOCK_MESSAGE); } } if (fusesFlag) { fusesFlag = 0; rFlag = writeFuses(WRITE_FUSES_HM, WRITE_FUSES_LM, fusesBits, \ W_FUSESLSB, W_FUSESLEN); if (rFlag == 9) { fprintf(stderr, "For the %s: Write_fuses not defined in _sp12dev.\n", device.name); } else if (rFlag == 2) { fprintf(stderr, "For the %s; Wrong number of fuse bits, expect %d.\n", device.name, W_FUSESLEN); } else { for (idx = 0; idx < (R_FUSESLEN - W_FUSESLEN) - W_FUSESLSB; idx++) printf(" "); printf("%s are the fuse bits written into an %s\n%s\n", fusesBits, device.name, FUSES_MESSAGE); } } if (highFFlag) { highFFlag = 0; rFlag = writeFuses(WRITE_HIGH_FUSES_HM, WRITE_HIGH_FUSES_LM, fusesBits, \ WH_FUSESLSB, WH_FUSESLEN); if (rFlag == 9) { fprintf(stderr, "For the %s: Write_high_fuses not defined in _sp12dev.\n", device.name); } else if (rFlag == 2) { fprintf(stderr, "For the %s; Wrong number of high fuse bits, expect %d.\n", device.name, WH_FUSESLEN); } else { for (idx = 0; idx < (RH_FUSESLEN - WH_FUSESLEN) - WH_FUSESLSB; idx++) printf(" "); printf("%s are the high fuse bits written into an %s\n%s\n", fusesBits, device.name, H_FUSES_MESSAGE); } } if (extdFFlag) { extdFFlag = 0; rFlag = writeFuses(WRITE_EXTD_FUSES_HM, WRITE_EXTD_FUSES_LM, fusesBits, \ WX_FUSESLSB, WX_FUSESLEN); if (rFlag == 9) { fprintf(stderr, "For the %s: Write_extd_fuses not defined in _sp12dev.\n", device.name); } else if (rFlag == 2) { fprintf(stderr, "For the %s; Wrong number of extended fuse bits, expect %d.\n", device.name, WX_FUSESLEN); } else { for (idx = 0; idx < (RX_FUSESLEN - WX_FUSESLEN) - WX_FUSESLSB; idx++) printf(" "); printf("%s are the extended fuse bits written into an %s\n%s\n", fusesBits, device.name, X_FUSES_MESSAGE); } } reportLEFHXcFlag(); overlayFlag = 0; } /* * if C --> (p || e) || ((p || e) && f) * Cp(f) --> read program area (file) into * device.flashLimit word array; * calculate checksum for array * Ce(f) --> read eeprom area (file) into * device.eepromLimit byte array; * calculate checksum for array * check for L, E, B, F, R, S but just report them */ if (checksumFlag) { checksumFlag = 0; if (eepromFlag) { eepromFlag = 0; if (pathAvailable) { pathAvailable = 0; if (readEepromFile(checksumPath, eepromBuf, device.eepromLimit) != 0) { printf("%s %s\n", checksumPath, FILE_ERROR); exitSp12(2); } else { printf("Checksum eeprom file %s: %04x\n", checksumPath, checksum(eepromBuf, device.eepromLimit)); } } else { readEepromArea(eepromBuf, device.eepromLimit); printf("Checksum eeprom area: %04x\n", checksum(eepromBuf, device.eepromLimit)); } } else if (flashFlag) { flashFlag = 0; if (pathAvailable) { pathAvailable = 0; if (readFlashFile(checksumPath, flashBuf, device.flashLimit) != 0) { printf("%s %s\n", checksumPath, FILE_ERROR); exitSp12(2); } else { printf("Checksum program file %s: %04x\n", checksumPath, checksum(flashBuf, device.flashLimit)); } } else { readFlashArea(flashBuf, device.flashLimit); printf("Checksum program area: %04x\n", checksum(flashBuf, device.flashLimit)); } } else { printf("you have selected option -C, but there is nothing\n"); printf("on the command line to calculate a checksum for.\n"); } reportLEFHXcFlag(); reportBflag(); } /* * If E --> chip erase */ if (eraseFlag) { eraseFlag = 0; printf("Performing chip erase...\n"); eraseDevice(); } /* * if B --> blank check */ if (blankChkFlag) { blankChkFlag = 0; blank_check(); } /* * if i --> do nothing (init already done, device already reported) * just clear initFlag */ initFlag = 0; } int main(int argc, char *argv[]) { int ascii; /* characters on command line */ int idx = 0; /* index arguments on command line */ char *dataPtr; /* for separating address:data */ int exitFlag = 0; char binary[9] = "76543210"; /* Stores conversion num to binary */ #if defined(__OpenBSD__) u_long iomap[32]; #endif device.initPerformed = 0; flashPath[0] = '\0'; eepromPath[0] = '\0'; checksumPath[0] = '\0'; sp12Start = clock(); #if defined(__WIN32__) win_giveio (); // get access to I/O ports in Windows NT/2000/XP #else /* * Take control of LPT I/O ports */ #if defined(__linux__) if (ioperm(0x278,3,1)) {perror("ioperm error at 0x278");exit(1);} if (ioperm(0x378,3,1)) {perror("ioperm error at 0x378");exit(1);} if (ioperm(0x3BC,3,1)) {perror("ioperm error at 0x3BC");exit(1);} #elif defined(__OpenBSD__) #define enable(a, i) do { \ ((a)[((i) + 0) >> 5] &= ~(1 << (((i) + 0) & 0x1F))); \ ((a)[((i) + 1) >> 5] &= ~(1 << (((i) + 1) & 0x1F))); \ ((a)[((i) + 2) >> 5] &= ~(1 << (((i) + 2) & 0x1F))); \ } while (0) if (i386_get_ioperm(iomap) != 0) { perror("i386_get_ioperm error"); exit(1); } enable(iomap, 0x278); enable(iomap, 0x378); enable(iomap, 0x3BC); if (i386_set_ioperm(iomap) != 0) { perror("i386_set_ioperm error"); exit(1); } #endif #endif /* * Revoke setuid/setguid-root status */ setgid(getgid()); setuid(getuid()); /* * Check if something is on the command line, print usage message * if not, else do init; if in sp12 mode, put power on the device * (using Centronics data bits as power source), enable serial * reading/programming */ if (argc < 2) { printf(USAGE, VERSION); exit(0); } else { printf("SP12 version %s performing init...\n", VERSION); initSp12(argv[0]); } /* * allocate our memory buffers */ flashBuf = malloc(FLASHBUF_UPPERLIMIT * sizeof (unsigned int)); if (flashBuf == NULL) { printf ("ERROR: No memory available for buffer!\n"); exitSp12(2); } eepromBuf = malloc(EEPROMBUF_UPPERLIMIT * sizeof (unsigned int)); if (eepromBuf == NULL) { printf ("ERROR: No memory available for buffer!\n"); exitSp12(2); } /* * Dissect the command line, acting on commands from left to right. */ idx = 0; while (++idx < argc) { if (*argv[idx] != '-' && fileFlag) { fileFlag = 0; if (addressFlag) { printf("Do not use options -f and -a in a single command.\n"); exitSp12(2); } if (checksumFlag && !readFlag && !writeFlag) { strlcpy(checksumPath, argv[idx], sizeof(checksumPath)); pathAvailable = 1; processCommand(); } else if (flashFlag) { strlcpy(flashPath, argv[idx], sizeof(flashPath)); pathAvailable = 1; processCommand(); } else if (eepromFlag) { strlcpy(eepromPath, argv[idx], sizeof(eepromPath)); pathAvailable = 1; processCommand(); } else { printf("Option -f must be combined with option -e, -p or -C\n"); exitSp12(2); } } else if (*argv[idx] != '-' && addressFlag) { addressFlag = 0; dataPtr = argv[idx]; if (writeFlag && (dataPtr = strchr(argv[idx], ':')) == NULL) { printf("Option -wa must be followed by address:data\n"); exitSp12(2); } if (writeFlag) dataPtr[0] = '\0'; if (flashFlag) { flashAddress =str2num(argv[idx]); if (writeFlag) flashData = str2num(++dataPtr); addressAvailable = 1; processCommand(); } else if (eepromFlag) { eepromAddress =str2num(argv[idx]); if (writeFlag) eepromData = str2num(++dataPtr); addressAvailable = 1; processCommand(); } else { printf("Option -a must be combined with option -e or -p\n"); exitSp12(2); } } else if (*argv[idx] != '-') { printf("No -a or -f option preceding argument `%s'\n", argv[idx]); } if (*argv[idx] == '-') { if (strchr(argv[idx], 'w') != NULL) strlcpy(commandStr, argv[idx], sizeof(commandStr)); while ((ascii = *++argv[idx]) != '\0') { switch(ascii) { case 'i': if (strlen(argv[idx]) > 1) { initFlag = 1; strlcpy(identifier, ++argv[idx], sizeof(identifier)); argv[idx][1] = '\0'; } if (idx > 1) { printf("WARNING: option -i[NN] has no effect unless\n"); printf(" it is first on the command line.\n"); } break; case 'T': if (strlen(argv[idx]) > 1) testFlag = atoi(++argv[idx]); break; case 'M': if (strlen(argv[idx]) > 1) { clkSpeed = atof(++argv[idx]); if (clkSpeed <= 0.1) clkSpeed = 0.1; argv[idx][1] = '\0'; } break; case 'P': if (strlen(argv[idx]) > 1) { if (argv[idx][2] == 'x') portFlag = (int) strtol(++argv[idx], NULL, 16); else portFlag = (int) strtol(++argv[idx], NULL, 10); if ((idx + 1) == argc) exitFlag = 1; else exitFlag = 0; portControl(portFlag, exitFlag); num2bin((unsigned char) portFlag, binary); printf("Writing %#04x (%d, B%s) ", portFlag, portFlag, binary); printf("to the parallel port data bits.\n"); if ((idx + 1) < argc) portFlag = 0; argv[idx][1] = '\0'; } break; case 'p': flashFlag = 1; break; case 'e': eepromFlag = 1; break; case 'w': writeFlag = 1; break; case 'r': readFlag = 1; break; case 'L': if (strlen(argv[idx]) > 1 \ && (*(argv[idx] + 1) == '0' || *(argv[idx] + 1) == '1')) { strlcpy(lockBits, ++argv[idx], sizeof(lockBits)); argv[idx][1] = '\0'; } lockFlag = 1; break; case '0': if (optimizeFlag) optimizeFlag = 10; break; case '1': if (optimizeFlag && !POLL_RDY_BSY) optimizeFlag = 11; break; case '2': break; case '3': break; case '4': break; case '5': break; case '6': break; case '7': break; case '8': break; case '9': break; case 'f': fileFlag = 1; break; case 'a': addressFlag = 1; break; case 'E': eraseFlag = 1; break; case 'B': blankChkFlag = 1; break; case 'C': checksumFlag = 1; break; case 'F': if (strlen(argv[idx]) > 1 \ && (*(argv[idx] + 1) == '0' || *(argv[idx] + 1) == '1')) { strlcpy(fusesBits, ++argv[idx], sizeof(fusesBits)); argv[idx][1] = '\0'; } fusesFlag = 1; break; case 'H': if (strlen(argv[idx]) > 1 \ && (*(argv[idx] + 1) == '0' || *(argv[idx] + 1) == '1')) { strlcpy(fusesBits, ++argv[idx], sizeof(fusesBits)); argv[idx][1] = '\0'; } highFFlag = 1; break; case 'X': if (strlen(argv[idx]) > 1 \ && (*(argv[idx] + 1) == '0' || *(argv[idx] + 1) == '1')) { strlcpy(fusesBits, ++argv[idx], sizeof(fusesBits)); argv[idx][1] = '\0'; } extdFFlag = 1; break; case 'I': IntelFlag = 1; break; case 'c': if (strlen(argv[idx]) > 1 \ && (*(argv[idx] + 1) == '0' || *(argv[idx] + 1) == '1')) { calibAddress = strtoul(++argv[idx], NULL, 2); argv[idx][1] = '\0'; } if (strlen(argv[idx]) > 1 \ && (*(argv[idx] + 1) != '0' && *(argv[idx] + 1) != '1')) { calibAddress = strtoul(++argv[idx], NULL, 10); argv[idx][1] = '\0'; } calibFlag = 1; break; case 'h': hexAsciiFlag = 1; break; case 'o': optimizeFlag = 1; break; case 's': supported(); exitSp12(0); break; case 't': idx = 0; printf("(-t)iming check, about 10 seconds\n"); printf("..................................................\r"); for (idx = 0; idx < 50; idx++) { loopDelay(timeConst.resetPuls * 4); putchar('o'); fflush(stdout); } printf(" STOP\n"); exitSp12(0); break; case 'O': overlayFlag = 1; break; default: printf("The character `%c' ", ascii); printf("is not a valid option.\n"); break; } } if (!fileFlag && !addressFlag) processCommand(); } } if (fileFlag) { printf("Option f used, but no path on command line.\n"); printf("Nothing to do for sp12.\n"); exitSp12(2); } /* * Exiting with the byte `portFlag' on the parallel port data bits. * When the -Tnn option is not (also) used as the final option on * the command line, this defaults to 0x00. */ if (SCK == S_SCK && testFlag) { switch(testFlag) { case 1: portFlag = RESET; break; case 2: portFlag = RESET | PORTPOWER; break; default: break; } } else if (testFlag) { printf("Option -T is not available in Kanda compatible mode.\n"); } if (!portFlag) { portFlag = DEFAULT_EXIT_STATE; num2bin((unsigned char) portFlag, binary); printf("Writing %#04x (%d, B%s) ", portFlag, portFlag, binary); printf("to the parallel port data bits.\n"); } portControl(portFlag, 1); if (SCK == S_SCK) { if (portFlag & 0x02) printf("Reset was left high.\n"); if (portFlag & 0x7C) printf("One or more `power' bits were left high.\n"); } sp12End = clock(); sp12Elapsed = ((double) (sp12End - sp12Start)) / CLOCKS_PER_SEC; printf("Sp12 was active for %#3.2f seconds.\n", sp12Elapsed); return(0); }