mirror of
https://github.com/avrdudes/avrdude.git
synced 2026-09-29 12:28:41 +03:00
Consider bootrow and pdicfg for terminal cache and dryrun
This commit is contained in:
19
src/avr.c
19
src/avr.c
@@ -1165,10 +1165,10 @@ int avr_signature(const PROGRAMMER *pgm, const AVRPART *p) {
|
||||
int avr_mem_bitmask(const AVRPART *p, const AVRMEM *mem, int addr) {
|
||||
int bitmask = mem->bitmask;
|
||||
// Collective memory fuses will have a different bitmask for each address (ie, fuse)
|
||||
if(str_eq(mem->desc, "fuses") && addr < 10) { // Get right fuse in fuses memory
|
||||
if(str_eq(mem->desc, "fuses") && addr >=0 && addr < 16) { // Get right fuse in fuses memory
|
||||
char memtype[64];
|
||||
AVRMEM *dfuse;
|
||||
sprintf(memtype, "fuse%d", addr);
|
||||
sprintf(memtype, "fuse%x", addr);
|
||||
if((dfuse = avr_locate_mem(p, memtype)) && dfuse->size == 1)
|
||||
bitmask = dfuse->bitmask;
|
||||
}
|
||||
@@ -1401,11 +1401,12 @@ const char *avr_mem_order[100] = {
|
||||
"fuse4", "tcd0cfg", "fuse5", "syscfg0",
|
||||
"fuse6", "syscfg1", "fuse7", "append",
|
||||
"codesize", "fuse8", "fuse9", "bootend",
|
||||
"bootsize", "fuses", "lock", "lockbits",
|
||||
"tempsense", "signature", "prodsig", "sernum",
|
||||
"calibration", "osccal16", "osccal20", "osc16err",
|
||||
"osc20err", "usersig", "userrow", "data",
|
||||
"io", "sib",
|
||||
"bootsize", "fusea" "pdicfg", "fuses",
|
||||
"lock", "lockbits", "tempsense", "signature",
|
||||
"prodsig", "sernum", "calibration", "osccal16",
|
||||
"osccal20", "osc16err", "osc20err", "bootrow",
|
||||
"usersig", "userrow", "data", "io",
|
||||
"sib",
|
||||
};
|
||||
|
||||
void avr_add_mem_order(const char *str) {
|
||||
@@ -1441,8 +1442,8 @@ int avr_mem_is_eeprom_type(const AVRMEM *mem) {
|
||||
return avr_memtype_is_eeprom_type(mem->desc);
|
||||
}
|
||||
|
||||
int avr_memtype_is_usersig_type(const char *memtype) {
|
||||
return memtype && (str_eq(memtype, "usersig") || str_eq(memtype, "userrow"));
|
||||
int avr_memtype_is_usersig_type(const char *memtype) { // Bootrow is subsumed under usersig type
|
||||
return memtype && (str_eq(memtype, "bootrow") || str_eq(memtype, "usersig") || str_eq(memtype, "userrow"));
|
||||
}
|
||||
|
||||
int avr_mem_is_usersig_type(const AVRMEM *mem) {
|
||||
|
||||
@@ -50,30 +50,31 @@
|
||||
* int avr_reset_cache(const PROGRAMMER *pgm, const AVRPART *p);
|
||||
*
|
||||
* avr_read_byte_cached() and avr_write_byte_cached() use a cache if paged
|
||||
* routines are available and if the device memory type is flash, EEPROM or
|
||||
* usersig. The AVRXMEGA memories application, apptable and boot are subsumed
|
||||
* under flash. Userrow is subsumed under usersig provided avrdude.conf has a
|
||||
* memory alias from usersig to userrow. In all other cases the cached
|
||||
* read/write functions fall back to pgm->read_byte() and pgm->write_byte(),
|
||||
* respectively. Bytewise cached read always gets its data from the cache,
|
||||
* possibly after reading a page from the device memory. Bytewise cached
|
||||
* write with an address in memory range only ever modifies the cache. Any
|
||||
* modifications are written to the device after calling avr_flush_cache() or
|
||||
* when attempting to read or write from a location outside the address range
|
||||
* of the device memory.
|
||||
* routines are available and if the device memory type is flash, EEPROM,
|
||||
* bootrow or usersig. The AVRXMEGA memories application, apptable and boot
|
||||
* are subsumed under flash. Userrow is subsumed under usersig provided
|
||||
* avrdude.conf has a memory alias from usersig to userrow. In all other
|
||||
* cases the cached read/write functions fall back to pgm->read_byte() and
|
||||
* pgm->write_byte(), respectively. Bytewise cached read always gets its data
|
||||
* from the cache, possibly after reading a page from the device memory.
|
||||
* Bytewise cached write with an address in memory range only ever modifies
|
||||
* the cache. Any modifications are written to the device after calling
|
||||
* avr_flush_cache() or when attempting to read or write from a location
|
||||
* outside the address range of the device memory.
|
||||
*
|
||||
* avr_flush_cache() synchronises pending writes to flash, EEPROM and usersig
|
||||
* with the device. With some programmer and part combinations, flash (and
|
||||
* sometimes EEPROM, too) looks like a NOR memory, ie, a write can only clear
|
||||
* bits, never set them. For NOR memories a page erase or, if not available,
|
||||
* a chip erase needs to be issued before writing arbitrary data. Usersig is
|
||||
* generally unaffected by a chip erase, so will need a page erase. When a
|
||||
* memory looks like a NOR memory, either page erase is deployed (eg, with
|
||||
* parts that have PDI/UPDI interfaces), or if that is not available, both
|
||||
* EEPROM and flash caches are fully read in, a pgm->chip_erase() command is
|
||||
* issued and both EEPROM and flash are written back to the device. Hence, it
|
||||
* can take minutes to ensure that a single previously cleared bit is set
|
||||
* and, therefore, this routine should be called sparingly.
|
||||
* avr_flush_cache() synchronises pending writes to flash, EEPROM, bootrow
|
||||
* and usersig with the device. With some programmer and part combinations,
|
||||
* flash (and sometimes EEPROM, too) looks like a NOR memory, ie, a write can
|
||||
* only clear bits, never set them. For NOR memories a page erase or, if not
|
||||
* available, a chip erase needs to be issued before writing arbitrary data.
|
||||
* Bootrow and usersig are generally unaffected by a chip erase, so will need
|
||||
* a page erase. When a memory looks like a NOR memory, either page erase is
|
||||
* deployed (eg, with parts that have PDI/UPDI interfaces), or if that is not
|
||||
* available, both EEPROM and flash caches are fully read in, a
|
||||
* pgm->chip_erase() command is issued and both EEPROM and flash are written
|
||||
* back to the device. Hence, it can take minutes to ensure that a single
|
||||
* previously cleared bit is set and, therefore, this routine should be
|
||||
* called sparingly.
|
||||
*
|
||||
* avr_chip_erase_cached() erases the chip and discards pending writes() to
|
||||
* flash or EEPROM. It presets the flash cache to all 0xff alleviating the
|
||||
@@ -90,7 +91,7 @@
|
||||
* has these clear bits on the device. Only with this evidence is the EEPROM
|
||||
* cache preset to all 0xff otherwise the cache discards all pending writes
|
||||
* to EEPROM and is left unchanged otherwise. avr_chip_erase_cached() does not
|
||||
* affect the usersig cache.
|
||||
* affect the bootrow or usersig cache.
|
||||
*
|
||||
* The avr_page_erase_cached() function erases a page and synchronises it
|
||||
* with the cache.
|
||||
@@ -120,7 +121,7 @@
|
||||
* - Programmer must have paged routines
|
||||
* - Memory has positive page size, which is a power of two
|
||||
* - Memory has positive size, which is a multiple of the page size
|
||||
* - Memory is flash, EEPROM or usersig type
|
||||
* - Memory is flash, EEPROM, bootrow or usersig type
|
||||
*
|
||||
* Note that in this definition the page size can be 1
|
||||
*/
|
||||
@@ -256,7 +257,7 @@ static int loadCachePage(AVR_Cache *cp, const PROGRAMMER *pgm, const AVRPART *p,
|
||||
|
||||
static int initCache(AVR_Cache *cp, const PROGRAMMER *pgm, const AVRPART *p) {
|
||||
AVRMEM *basemem = avr_locate_mem(p,
|
||||
cp == pgm->cp_flash? "flash": cp == pgm->cp_eeprom? "eeprom": "usersig");
|
||||
cp == pgm->cp_flash? "flash": cp == pgm->cp_eeprom? "eeprom": cp == pgm->cp_bootrow? "bootrow": "usersig");
|
||||
|
||||
if(!basemem || !avr_has_paged_access(pgm, basemem))
|
||||
return LIBAVRDUDE_GENERAL_FAILURE;
|
||||
@@ -357,11 +358,12 @@ typedef struct {
|
||||
} CacheDesc_t;
|
||||
|
||||
|
||||
// Write flash, EEPROM and usersig caches to device and free them
|
||||
// Write flash, EEPROM, bootrow and usersig caches to device and free them
|
||||
int avr_flush_cache(const PROGRAMMER *pgm, const AVRPART *p) {
|
||||
CacheDesc_t mems[3] = {
|
||||
CacheDesc_t mems[] = {
|
||||
{ avr_locate_mem(p, "flash"), pgm->cp_flash, 1, 0, -1, 0 },
|
||||
{ avr_locate_mem(p, "eeprom"), pgm->cp_eeprom, 0, 1, -1, 0 },
|
||||
{ avr_locate_mem(p, "bootrow"), pgm->cp_bootrow, 0, 0, -1, 0 },
|
||||
{ avr_locate_mem(p, "usersig"), pgm->cp_usersig, 0, 0, -1, 0 },
|
||||
};
|
||||
|
||||
@@ -453,7 +455,7 @@ int avr_flush_cache(const PROGRAMMER *pgm, const AVRPART *p) {
|
||||
AVR_Cache *cp = mems[i].cp;
|
||||
if(!mem)
|
||||
continue;
|
||||
if(avr_mem_is_usersig_type(mem)) // CE does not affect usersig
|
||||
if(avr_mem_is_usersig_type(mem)) // CE does not affect bootrow/usersig
|
||||
continue;
|
||||
|
||||
for(int pgno = 0, n = 0; n < cp->size; pgno++, n += cp->page_size)
|
||||
@@ -469,7 +471,7 @@ int avr_flush_cache(const PROGRAMMER *pgm, const AVRPART *p) {
|
||||
AVR_Cache *cp = mems[i].cp;
|
||||
if(!mem)
|
||||
continue;
|
||||
if(avr_mem_is_usersig_type(mem)) // CE does not affect usersig
|
||||
if(avr_mem_is_usersig_type(mem)) // CE does not affect bootrow/usersig
|
||||
continue;
|
||||
|
||||
for(int ird = 0, pgno = 0, n = 0; n < cp->size; pgno++, n += cp->page_size) {
|
||||
@@ -498,7 +500,7 @@ int avr_flush_cache(const PROGRAMMER *pgm, const AVRPART *p) {
|
||||
AVR_Cache *cp = mems[i].cp;
|
||||
if(!mem)
|
||||
continue;
|
||||
if(avr_mem_is_usersig_type(mem)) // CE does not affect usersig
|
||||
if(avr_mem_is_usersig_type(mem)) // CE does not affect bootrow/usersig
|
||||
continue;
|
||||
|
||||
if(mems[i].isflash) {
|
||||
@@ -590,7 +592,7 @@ int avr_flush_cache(const PROGRAMMER *pgm, const AVRPART *p) {
|
||||
|
||||
/*
|
||||
* Read byte via a read/write cache
|
||||
* - Used if paged routines available and if memory is flash, EEPROM or usersig
|
||||
* - Used if paged routines available and if memory is flash, EEPROM, bootrow or usersig
|
||||
* - Otherwise fall back to pgm->read_byte()
|
||||
* - Out of memory addr: synchronise cache and, if successful, pretend reading a zero
|
||||
* - Cache is automagically created and initialised if needed
|
||||
@@ -598,7 +600,7 @@ int avr_flush_cache(const PROGRAMMER *pgm, const AVRPART *p) {
|
||||
int avr_read_byte_cached(const PROGRAMMER *pgm, const AVRPART *p, const AVRMEM *mem,
|
||||
unsigned long addr, unsigned char *value) {
|
||||
|
||||
// Use pgm->read_byte() if not flash/EEPROM/usersig or no paged access
|
||||
// Use pgm->read_byte() if not flash/EEPROM/bootrow/usersig or no paged access
|
||||
if(!avr_has_paged_access(pgm, mem))
|
||||
return fallback_read_byte(pgm, p, mem, addr, value);
|
||||
|
||||
@@ -611,7 +613,8 @@ int avr_read_byte_cached(const PROGRAMMER *pgm, const AVRPART *p, const AVRMEM *
|
||||
}
|
||||
|
||||
AVR_Cache *cp = avr_mem_is_eeprom_type(mem)? pgm->cp_eeprom:
|
||||
avr_mem_is_usersig_type(mem)? pgm->cp_usersig: pgm->cp_flash;
|
||||
avr_mem_is_flash_type(mem)? pgm->cp_flash:
|
||||
str_eq(mem->desc, "bootrow")? pgm->cp_bootrow: pgm->cp_usersig;
|
||||
|
||||
if(!cp->cont) // Init cache if needed
|
||||
if(initCache(cp, pgm, p) < 0)
|
||||
@@ -633,7 +636,7 @@ int avr_read_byte_cached(const PROGRAMMER *pgm, const AVRPART *p, const AVRMEM *
|
||||
|
||||
/*
|
||||
* Write byte via a read/write cache
|
||||
* - Used if paged routines available and if memory is flash, EEPROM or usersig
|
||||
* - Used if paged routines available and if memory is flash, EEPROM, bootrow or usersig
|
||||
* - Otherwise fall back to pgm->write_byte()
|
||||
* - Out of memory addr: synchronise cache with device and return whether successful
|
||||
* - If programmer indicates a readonly spot, return LIBAVRDUDE_SOFTFAIL
|
||||
@@ -642,7 +645,7 @@ int avr_read_byte_cached(const PROGRAMMER *pgm, const AVRPART *p, const AVRMEM *
|
||||
int avr_write_byte_cached(const PROGRAMMER *pgm, const AVRPART *p, const AVRMEM *mem,
|
||||
unsigned long addr, unsigned char data) {
|
||||
|
||||
// Use pgm->write_byte() if not flash/EEPROM/usersig or no paged access
|
||||
// Use pgm->write_byte() if not flash/EEPROM/bootrow/usersig or no paged access
|
||||
if(!avr_has_paged_access(pgm, mem))
|
||||
return fallback_write_byte(pgm, p, mem, addr, data);
|
||||
|
||||
@@ -651,7 +654,8 @@ int avr_write_byte_cached(const PROGRAMMER *pgm, const AVRPART *p, const AVRMEM
|
||||
return avr_flush_cache(pgm, p);
|
||||
|
||||
AVR_Cache *cp = avr_mem_is_eeprom_type(mem)? pgm->cp_eeprom:
|
||||
avr_mem_is_usersig_type(mem)? pgm->cp_usersig: pgm->cp_flash;
|
||||
avr_mem_is_flash_type(mem)? pgm->cp_flash:
|
||||
str_eq(mem->desc, "bootrow")? pgm->cp_bootrow: pgm->cp_usersig;
|
||||
|
||||
if(!cp->cont) // Init cache if needed
|
||||
if(initCache(cp, pgm, p) < 0)
|
||||
@@ -682,7 +686,7 @@ int avr_chip_erase_cached(const PROGRAMMER *pgm, const AVRPART *p) {
|
||||
CacheDesc_t mems[3] = {
|
||||
{ avr_locate_mem(p, "flash"), pgm->cp_flash, 1, 0, -1, 0 },
|
||||
{ avr_locate_mem(p, "eeprom"), pgm->cp_eeprom, 0, 1, -1, 0 },
|
||||
// usersig is unaffected by CE
|
||||
// bootrow/usersig is unaffected by CE
|
||||
};
|
||||
int rc;
|
||||
|
||||
@@ -754,7 +758,8 @@ int avr_page_erase_cached(const PROGRAMMER *pgm, const AVRPART *p, const AVRMEM
|
||||
}
|
||||
|
||||
AVR_Cache *cp = avr_mem_is_eeprom_type(mem)? pgm->cp_eeprom:
|
||||
avr_mem_is_usersig_type(mem)? pgm->cp_usersig: pgm->cp_flash;
|
||||
avr_mem_is_flash_type(mem)? pgm->cp_flash:
|
||||
str_eq(mem->desc, "bootrow")? pgm->cp_bootrow: pgm->cp_usersig;
|
||||
|
||||
if(!cp->cont) // Init cache if needed
|
||||
if(initCache(cp, pgm, p) < 0)
|
||||
@@ -780,7 +785,7 @@ int avr_page_erase_cached(const PROGRAMMER *pgm, const AVRPART *p, const AVRMEM
|
||||
|
||||
// Free cache(s) discarding any pending writes
|
||||
int avr_reset_cache(const PROGRAMMER *pgm, const AVRPART *p_unused) {
|
||||
AVR_Cache *mems[3] = { pgm->cp_flash, pgm->cp_eeprom, pgm->cp_usersig };
|
||||
AVR_Cache *mems[] = { pgm->cp_flash, pgm->cp_eeprom, pgm->cp_bootrow, pgm->cp_usersig };
|
||||
|
||||
for(size_t i = 0; i < sizeof mems/sizeof*mems; i++) {
|
||||
AVR_Cache *cp = mems[i];
|
||||
|
||||
36
src/dryrun.c
36
src/dryrun.c
@@ -29,6 +29,7 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <ctype.h>
|
||||
#include <unistd.h>
|
||||
#include <stdarg.h>
|
||||
#include <time.h>
|
||||
@@ -113,7 +114,7 @@ static void dryrun_enable(PROGRAMMER *pgm, const AVRPART *p) {
|
||||
pmsg_debug("%s()\n", __func__);
|
||||
|
||||
if(!dry.dp) {
|
||||
unsigned char inifuses[10]; // For fuses, which is made up from fuse0, fuse1, ...
|
||||
unsigned char inifuses[16]; // For fuses, which is made up from fuse0, fuse1, ...
|
||||
AVRMEM *fusesm = NULL;
|
||||
dry.dp = avr_dup_part(p); // Allocate dryrun part
|
||||
|
||||
@@ -126,13 +127,14 @@ static void dryrun_enable(PROGRAMMER *pgm, const AVRPART *p) {
|
||||
} else if(str_eq(m->desc, "fuses")) {
|
||||
fusesm = m;
|
||||
} else if(str_contains(m->desc, "fuse") || str_contains(m->desc, "lock")) {
|
||||
// Lock can have 4 bytes: still allow initialisation from initval
|
||||
// Lock, eg, can have 4 bytes: still allow initialisation from initval
|
||||
if(m->initval != -1 && m->size >=1 && m->size <= (int) sizeof(m->initval)) {
|
||||
memcpy(m->buf, &m->initval, m->size); // FIXME: relying on little endian here
|
||||
if(str_starts(m->desc, "fuse") && m->desc[4] && m->size == 1) {
|
||||
int fno = m->desc[4]-'0';
|
||||
if(fno >= 0 && fno < (int) sizeof inifuses)
|
||||
inifuses[fno] = m->initval;
|
||||
if(str_starts(m->desc, "fuse") && m->desc[4] && isxdigit(0xff & m->desc[4]) && !m->desc[5]) {
|
||||
int fno = strtol(m->desc+4, NULL, 16);
|
||||
if(fno >= 0)
|
||||
for(int i = 0; i < m->size && fno+i < (int) sizeof inifuses; i++)
|
||||
inifuses[fno+i] = m->initval >> 8*i;
|
||||
}
|
||||
} else {
|
||||
memset(m->buf, 0xff, m->size);
|
||||
@@ -333,16 +335,22 @@ int dryrun_write_byte(const PROGRAMMER *pgm, const AVRPART *p, const AVRMEM *m,
|
||||
|
||||
dmem->buf[addr] = data;
|
||||
|
||||
if(str_eq(dmem->desc, "fuses") && addr < 10) { // Copy the byte to corresponding fuse[0-9]
|
||||
if(str_eq(dmem->desc, "fuses") && addr < 16) { // Copy the byte to corresponding fuse[0-9a-f]
|
||||
char memtype[64];
|
||||
sprintf(memtype, "fuse%ld", addr);
|
||||
if((dfuse = avr_locate_mem(dry.dp, memtype)) && dfuse->size == 1)
|
||||
sprintf(memtype, "fuse%lx", addr);
|
||||
if((dfuse = avr_locate_mem(dry.dp, memtype)))
|
||||
dfuse->buf[0] = data;
|
||||
} else if(str_starts(m->desc, "fuse")) { // Copy fuseN byte into fuses memory
|
||||
int fno = m->desc[4]-'0';
|
||||
if(fno >= 0 && fno < 10)
|
||||
if((dfuse = avr_locate_mem(dry.dp, "fuses")) && dfuse->size > fno)
|
||||
dfuse->buf[fno] = data;
|
||||
else if(addr > 0) { // Could be high byte of two-byte fuse
|
||||
sprintf(memtype, "fuse%lx", addr-1);
|
||||
if((dfuse = avr_locate_mem(dry.dp, memtype)))
|
||||
dfuse->buf[1] = data;
|
||||
}
|
||||
} else if(str_starts(m->desc, "fuse") && m->desc[4] && isxdigit(0xff & m->desc[4]) && !m->desc[5]) {
|
||||
// Copy fuseX byte into fuses memory
|
||||
int fno = strtol(m->desc+4, NULL, 16);
|
||||
if(fno >= 0)
|
||||
if((dfuse = avr_locate_mem(dry.dp, "fuses")) && (int) (fno+addr) < dfuse->size)
|
||||
dfuse->buf[fno+addr] = data;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
@@ -782,7 +782,7 @@ static int elf_mem_limits(const AVRMEM *mem, const AVRPART *p,
|
||||
*lowbound = 0x810000;
|
||||
*highbound = 0x81ffff; // Max 64 KiB
|
||||
*fileoff = 0;
|
||||
} else if (str_eq(mem->desc, "lfuse") || str_eq(mem->desc, "fuses")) {
|
||||
} else if (str_eq(mem->desc, "lfuse") || str_eq(mem->desc, "fuse") || str_eq(mem->desc, "fuses")) {
|
||||
*lowbound = 0x820000;
|
||||
*highbound = 0x82ffff;
|
||||
*fileoff = 0;
|
||||
@@ -795,11 +795,11 @@ static int elf_mem_limits(const AVRMEM *mem, const AVRPART *p,
|
||||
*highbound = 0x82ffff;
|
||||
*fileoff = 2;
|
||||
} else if (str_starts(mem->desc, "fuse") &&
|
||||
(mem->desc[4] >= '0' && mem->desc[4] <= '9')) {
|
||||
/* Xmega fuseN */
|
||||
mem->desc[4] && isxdigit(0xff & mem->desc[4]) && ¬mem->desc[5]) {
|
||||
/* Xmega or modern AVR fuseX */
|
||||
*lowbound = 0x820000;
|
||||
*highbound = 0x82ffff;
|
||||
*fileoff = mem->desc[4] - '0';
|
||||
*fileoff = strtol(mem->desc+4, NULL, 16);
|
||||
} else if (str_starts(mem->desc, "lock")) { // Lock or lockbits
|
||||
*lowbound = 0x830000;
|
||||
*highbound = 0x83ffff;
|
||||
|
||||
@@ -843,7 +843,7 @@ typedef struct programmer_t {
|
||||
unsigned int addr);
|
||||
int (*flush_cache) (const struct programmer_t *pgm, const AVRPART *p);
|
||||
int (*reset_cache) (const struct programmer_t *pgm, const AVRPART *p);
|
||||
AVR_Cache *cp_flash, *cp_eeprom, *cp_usersig;
|
||||
AVR_Cache *cp_flash, *cp_eeprom, *cp_bootrow, *cp_usersig;
|
||||
|
||||
const char *config_file; // Config file where defined
|
||||
int lineno; // Config file line number
|
||||
|
||||
@@ -81,6 +81,7 @@ PROGRAMMER *pgm_new(void) {
|
||||
// Allocate cache structures for flash and EEPROM, *do not* free in pgm_free()
|
||||
pgm->cp_flash = cfg_malloc("pgm_new()", sizeof(AVR_Cache));
|
||||
pgm->cp_eeprom = cfg_malloc("pgm_new()", sizeof(AVR_Cache));
|
||||
pgm->cp_bootrow = cfg_malloc("pgm_new()", sizeof(AVR_Cache));
|
||||
pgm->cp_usersig = cfg_malloc("pgm_new()", sizeof(AVR_Cache));
|
||||
|
||||
// Default values
|
||||
@@ -180,7 +181,7 @@ void pgm_free(PROGRAMMER *p) {
|
||||
}
|
||||
// Never free const char *, eg, p->desc, which are set by cache_string()
|
||||
// p->cookie is freed by pgm_teardown
|
||||
// Never free cp_flash, cp_eeprom or cp_usersig cache structures
|
||||
// Never free cp_flash, cp_eeprom, cp_bootrow or cp_usersig cache structures
|
||||
free(p);
|
||||
}
|
||||
}
|
||||
@@ -197,6 +198,8 @@ PROGRAMMER *pgm_dup(const PROGRAMMER *src) {
|
||||
free(pgm->cp_flash);
|
||||
if(pgm->cp_eeprom)
|
||||
free(pgm->cp_eeprom);
|
||||
if(pgm->cp_bootrow)
|
||||
free(pgm->cp_bootrow);
|
||||
if(pgm->cp_usersig)
|
||||
free(pgm->cp_usersig);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user