diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 3fa57f67..68917971 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -43,7 +43,6 @@ jobs: build-essential automake libtool - gettext flex bison libelf-dev diff --git a/NEWS b/NEWS index 8acbbf1b..a8ed1d86 100644 --- a/NEWS +++ b/NEWS @@ -55,6 +55,9 @@ Changes since version 7.3: - JTAGICE3 EDBG communication mode relies on hardcoded USBVID #1838 - avrdude documentation typo(s) attemps #1852 - Conflicting types for op16_is_mnemo: enum/integer #1851 + - Writing BOOTROW for Curiosity Nano #1868 + - Should AVRDUDE be run as root? #1860 + - Auto-build avrdude.pdf from texinfo sources #1847 * Pull requests: @@ -129,6 +132,17 @@ Changes since version 7.3: - Refine auto-erase strategy #1862 - Provide -P usb:vid:pid for USB hid i/f and allow long -P usb:serno for usblib and hidapi #186 + - Initialise dryrun flash with realistic random code #1873 + - Writing BOOTROW for Curiosity Nano #1870 + - Refine programmer/part/memory compatibility modelling #1869 + - Provide dev option -c \*/u that shows udev rules #1867 + - Provide current avrdude.pdf documentation in repo root #1865 + - doc: Stop building and installing .ps and .dvi #1857 + - Improve autotools build (part 2/n) #1695 + - Use correct file locations in the documentation #1637 + - Deprecate obsolete features and options #1875 + - Add more hard-coded usbvid/pid to udev rules #1876 + - Fixes for jtag3 programmers and prep for jtagmkII #1877 * Internals: diff --git a/README.md b/README.md index 17e38622..55601d88 100644 --- a/README.md +++ b/README.md @@ -18,7 +18,7 @@ The latest version of AVRDUDE is always available here:\ ## Documentation -Documentation for current and previous releases is [on Github Pages](https://avrdudes.github.io/avrdude/). +Documentation for current and previous releases is [on Github Pages](https://avrdudes.github.io/avrdude/). Git main is documented only with the most recent [avrdude.pdf](https://github.com/avrdudes/avrdude/blob/main/avrdude.pdf). ## Getting AVRDUDE for Windows diff --git a/avrdude.pdf b/avrdude.pdf new file mode 100644 index 00000000..9ecebf53 Binary files /dev/null and b/avrdude.pdf differ diff --git a/src/Makefile.am b/src/Makefile.am index fc978271..5b995756 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -31,15 +31,19 @@ EXTRA_DIST = \ avrdude.spec \ bootstrap -CLEANFILES = \ - config_gram.c \ - config_gram.h \ - lexer.c +BUILT_SOURCES = +CLEANFILES = + +built_sources = +built_sources += config_gram.c +built_sources += config_gram.h +built_sources += lexer.c + +BUILT_SOURCES += $(built_sources) +CLEANFILES += $(built_sources) include build-helpers/versioninfo.mk -BUILT_SOURCES = $(CLEANFILES) - #SUBDIRS = doc #DIST_SUBDIRS = doc @@ -53,19 +57,16 @@ AM_YFLAGS = -d avrdude_CPPFLAGS = -DCONFIG_DIR=\"$(sysconfdir)\" -libavrdude_a_CPPFLAGS = -DCONFIG_DIR=\"$(sysconfdir)\" -libavrdude_la_CPPFLAGS = $(libavrdude_a_CPPFLAGS) +libavrdude_la_CPPFLAGS = -DCONFIG_DIR=\"$(sysconfdir)\" avrdude_CFLAGS = @ENABLE_WARNINGS@ -libavrdude_a_CFLAGS = @ENABLE_WARNINGS@ $(LIBGPIOD_CFLAGS) -libavrdude_la_CFLAGS = $(libavrdude_a_CFLAGS) +libavrdude_la_CFLAGS = @ENABLE_WARNINGS@ $(LIBGPIOD_CFLAGS) -avrdude_LDADD = $(top_builddir)/$(noinst_LIBRARIES) @LIBUSB_1_0@ @LIBHIDAPI@ @LIBUSB@ @LIBFTDI1@ @LIBFTDI@ @LIBHID@ @LIBELF@ @LIBPTHREAD@ @LIBSERIALPORT@ $(LIBGPIOD_LIBS) -lm +avrdude_LDADD = libavrdude.la @LIBUSB_1_0@ @LIBHIDAPI@ @LIBUSB@ @LIBFTDI1@ @LIBFTDI@ @LIBHID@ @LIBELF@ @LIBPTHREAD@ @LIBSERIALPORT@ $(LIBGPIOD_LIBS) -lm bin_PROGRAMS = avrdude -noinst_LIBRARIES = libavrdude.a lib_LTLIBRARIES = libavrdude.la # automake thinks these generated files should be in the distribution, @@ -77,13 +78,14 @@ lib_LTLIBRARIES = libavrdude.la # https://savannah.nongnu.org/bugs/index.php?func=detailitem&item_id=15536 # # for why we don't want to have them. -dist-hook: - rm -f \ - $(distdir)/lexer.c \ - $(distdir)/config_gram.c \ - $(distdir)/config_gram.h +# +# We could avoid this dist-hook altogether if we could require +# Automake >= 1.16.4 and just use its no-dist-built-sources flag. +dist-hook: dist-hook-no-dist-built-sources-workaround +dist-hook-no-dist-built-sources-workaround: + cd "$(distdir)" && rm -f $(built_sources) -libavrdude_a_SOURCES = \ +libavrdude_la_SOURCES = \ config_gram.y \ lexer.l \ arduino.h \ @@ -218,8 +220,7 @@ libavrdude_a_SOURCES = \ wiring.c \ xbee.h \ xbee.c -libavrdude_la_SOURCES = $(libavrdude_a_SOURCES) -libavrdude_la_LDFLAGS = -version-info 2:0 +libavrdude_la_LDFLAGS = -version-info @LIBAVRDUDE_VERSION_INFO@ include_HEADERS = libavrdude.h include_HEADERS += libavrdude-avrintel.h diff --git a/src/avr.c b/src/avr.c index 88c9ae70..55542f43 100644 --- a/src/avr.c +++ b/src/avr.c @@ -322,12 +322,6 @@ int avr_mem_hiaddr(const AVRMEM * mem) { int i, n; - // Deprecated: calling with NULL disables trailing 0xff optimisation (remove in v8.0) - if(!mem) { - cx->avr_disableffopt = 1; - return 0; - } - if(cx->avr_disableffopt) return mem->size; @@ -428,7 +422,7 @@ int avr_read_mem(const PROGRAMMER *pgm, const AVRPART *p, const AVRMEM *mem, con // HW programmers need a page size > 1, bootloader typ only offer paged r/w if ((pgm->paged_load && mem->page_size > 1 && mem->size % mem->page_size == 0) || - ((pgm->prog_modes & PM_SPM) && avr_has_paged_access(pgm, mem))) { + ((pgm->prog_modes & PM_SPM) && avr_has_paged_access(pgm, p, mem))) { /* * the programmer supports a paged mode read */ @@ -504,7 +498,7 @@ int avr_read_mem(const PROGRAMMER *pgm, const AVRPART *p, const AVRMEM *mem, con if (rc != LIBAVRDUDE_SUCCESS) { pmsg_error("unable to read byte at address 0x%04lx\n", i); if (rc == LIBAVRDUDE_GENERAL_FAILURE) { - pmsg_error("read operation not supported for memory %s\n", mem->desc); + // pmsg_error("read operation not supported for memory %s\n", mem->desc); report_progress(1, -1, NULL); led_set(pgm, LED_ERR); led_clr(pgm, LED_PGM); @@ -873,8 +867,8 @@ int avr_write_byte_default(const PROGRAMMER *pgm, const AVRPART *p, const AVRMEM rc = pgm->initialize(pgm, p); if (rc < 0) { pmsg_error("initialization failed (rc = %d):\n", rc); - imsg_error("cannot re-initialize device after programming the %s bits; you\n", mem->desc); - imsg_error("must manually power-down the device and restart %s to continue\n", progname); + imsg_error("cannot re-initialize device after programming the %s bits;\n", mem->desc); + imsg_error("manually power-down the device and restart %s to continue\n", progname); rc = -3; goto rcerror; } @@ -1054,7 +1048,7 @@ int avr_write_mem(const PROGRAMMER *pgm, const AVRPART *p, const AVRMEM *m, int // HW programmers need a page size > 1, bootloader typ only offer paged r/w if ((pgm->paged_load && m->page_size > 1 && m->size % m->page_size == 0) || - ((pgm->prog_modes & PM_SPM) && avr_has_paged_access(pgm, m))) { + ((pgm->prog_modes & PM_SPM) && avr_has_paged_access(pgm, p, m))) { /* * the programmer supports a paged mode write */ @@ -1384,14 +1378,14 @@ int avr_verify_mem(const PROGRAMMER *pgm, const AVRPART *p, const AVRPART *v, co // Mismatch is only in unused bits if ((buf1[i] | bitmask) != 0xff) { // Programmer returned unused bits as 0, must be the part/programmer - pmsg_warning("ignoring mismatch in unused bits of %s\n", a->desc); - imsg_warning("(device 0x%02x != input 0x%02x); to prevent this warning fix\n", buf1[i], buf2[i]); - imsg_warning("the part or programmer definition in the config file\n"); + pmsg_debug("ignoring mismatch in unused bits of %s\n", a->desc); + imsg_debug("(device 0x%02x != input 0x%02x); to prevent this warning fix\n", buf1[i], buf2[i]); + imsg_debug("the part or programmer definition in the config file\n"); } else { // Programmer returned unused bits as 1, must be the user - pmsg_warning("ignoring mismatch in unused bits of %s\n", a->desc); - imsg_warning("(device 0x%02x != input 0x%02x); to prevent this warning set\n", buf1[i], buf2[i]); - imsg_warning("unused bits to 1 when writing (double check with datasheet)\n"); + pmsg_debug("ignoring mismatch in unused bits of %s\n", a->desc); + imsg_debug("(device 0x%02x != input 0x%02x); to prevent this warning set\n", buf1[i], buf2[i]); + imsg_debug("unused bits to 1 when writing (double check with datasheet)\n"); } } } @@ -1599,6 +1593,22 @@ Memtable avr_mem_order[100] = { {"sib", MEM_SIB | MEM_READONLY}, }; +#include "dryrun.h" +#include "jtag3.h" +#include "jtagmkII.h" +#define is_type(pgm, what) ((pgm)->initpgm == what ## _initpgm) + +// Whether a memory is an exception that shouldn't be there for this particular i/face +int avr_mem_exclude(const PROGRAMMER *pgm, const AVRPART *p, const AVRMEM *mem) { + return + is_type(pgm, dryrun)? 0: // Never exclude dryrun memories + (mem_is_sib(mem) && is_type(pgm, jtagmkII_updi)) || // jtag2updi cannot deal with sib + // jtag3 cannot read beyond addr 6 on classic prodsig, so exclude memories in prodsig/sigrow + (is_type(pgm, jtag3) && mem_is_in_sigrow(mem) && is_classic(p) && both_jtag(pgm, p)) || + // Classic part usersig memories cannot be read/written using ISP + (mem_is_usersig(mem) && is_classic(p) && both_isp(pgm, p)); +} + int avr_get_mem_type(const char *str) { for(size_t i=0; i < sizeof avr_mem_order/sizeof *avr_mem_order; i++) { if(avr_mem_order[i].str && str_eq(avr_mem_order[i].str, str)) diff --git a/src/avr_opcodes.c b/src/avr_opcodes.c index 4eb9ceee..e6c1e07c 100644 --- a/src/avr_opcodes.c +++ b/src/avr_opcodes.c @@ -647,6 +647,18 @@ AVR_mnemo opcode_mnemo(int op, int avrlevel) { return MNEMO_NONE; } +// Is 16-bit opcode valid for AVR part with avrlevel architecture? +int op16_is_valid(int op16, int avrlevel) { + int mnemo = opcode_mnemo(op16, avrlevel); + return mnemo >= 0 && mnemo <= MNEMO_N; +} + +// Is 16-bit opcode valid and benign for AVR part with avrlevel architecture? +int op16_is_benign(int op16, int avrlevel) { // Benign means no I/O or SRAM is being read/written + int mnemo = opcode_mnemo(op16, avrlevel); + return mnemo >= 0 && mnemo <= MNEMO_N && !(avr_opcodes[mnemo].type & OTY_EXTERNAL); +} + // Opcodes in avr_opcodes[] that a part ought to be able to run int avr_get_archlevel(const AVRPART *p) { int ret = @@ -737,3 +749,34 @@ int z_width(int op16, AVR_mnemo *mnemop) { return 0; } + +// Where else could the PC of the 16-bit opcode op16 at address here move to other than here + 2? +int op16_target(int here, int op16) { + AVR_mnemo mnemo = opcode_mnemo(op16, PART_ALL | OP_AVR_ILL); + + if(mnemo >= 0 && mnemo < MNEMO_N) { + switch(avr_opcodes[mnemo].type & OTY_TYPE_MASK) { + case OTY_RJMX: // Relative call rcall, range [.-4096, .+4094] bytes + case OTY_RJMI: // Relative jump rjmp, range [.-4096, .+4094] bytes + return here + 2 + ((int16_t) (op16<<4) >> 3); + + case OTY_JMPI: // Jump to potentially anywhere in flash (jmp, ijmp, eijmp) + case OTY_JMPX: // Jump to potentially anywhere in flash (calls and ret/i) + return INT_MIN; + + case OTY_BRAI: // Conditional branch, range [.-128, .+126] bytes + return here + 2 + (int8_t) ((op16 & 0x3f8)>>2); + + case OTY_SKPI: // Conditional skip, range [.+0, .+4] (cpse, sbrc, sbrs) + case OTY_SKPX: // Conditional skip, range [.+0, .+4] (sbic, sbis) + return here + 2 + 4; + } + } + + return here + 2; +} + +// Rjmp opcode from byte distance; 0xcfff is an endless loop, 0xc000 is a nop +int dist2rjmp(int dist) { + return 0xc000 | (((dist >> 1) - 1) & 0x0fff); +} diff --git a/src/avrcache.c b/src/avrcache.c index c4b7a2db..590cec54 100644 --- a/src/avrcache.c +++ b/src/avrcache.c @@ -99,7 +99,7 @@ * This file also holds the following utility functions * * // Does the programmer/memory combo have paged memory access? - * int avr_has_paged_access(const PROGRAMMER *pgm, const AVRMEM *mem); + * int avr_has_paged_access(const PROGRAMMER *pgm, const AVRPART *p, const AVRMEM *mem); * * // Read the page containing addr from the device into buf * int avr_read_page_default(const PROGRAMMER *pgm, const AVRPART *p, const AVRMEM *mem, int addr, unsigned char *buf); @@ -123,11 +123,12 @@ * Note that in this definition the page size can be 1 */ -int avr_has_paged_access(const PROGRAMMER *pgm, const AVRMEM *mem) { +int avr_has_paged_access(const PROGRAMMER *pgm, const AVRPART *p, const AVRMEM *mem) { return pgm->paged_load && pgm->paged_write && mem->page_size > 0 && (mem->page_size & (mem->page_size-1)) == 0 && mem->size > 0 && mem->size % mem->page_size == 0 && - mem_is_paged_type(mem); + mem_is_paged_type(mem) && + !(p && avr_mem_exclude(pgm, p, mem)); } @@ -145,7 +146,7 @@ int avr_has_paged_access(const PROGRAMMER *pgm, const AVRMEM *mem) { * + LIBAVRDUDE_SUCCESS (0) if the fallback of bytewise read succeeded */ int avr_read_page_default(const PROGRAMMER *pgm, const AVRPART *p, const AVRMEM *mem, int addr, unsigned char *buf) { - if(!avr_has_paged_access(pgm, mem) || addr < 0 || addr >= mem->size) + if(!avr_has_paged_access(pgm, p, mem) || addr < 0 || addr >= mem->size) return LIBAVRDUDE_GENERAL_FAILURE; int rc, pgsize = mem->page_size, base = addr & ~(pgsize-1); @@ -190,7 +191,7 @@ int avr_read_page_default(const PROGRAMMER *pgm, const AVRPART *p, const AVRMEM * - Uses write_byte() if memory page size is one, otherwise paged_write() */ int avr_write_page_default(const PROGRAMMER *pgm, const AVRPART *p, const AVRMEM *mem, int addr, unsigned char *data) { - if(!avr_has_paged_access(pgm, mem) || addr < 0 || addr >= mem->size) + if(!avr_has_paged_access(pgm, p, mem) || addr < 0 || addr >= mem->size) return LIBAVRDUDE_GENERAL_FAILURE; int rc, pgsize = mem->page_size, base = addr & ~(pgsize-1); @@ -263,7 +264,7 @@ static int initCache(AVR_Cache *cp, const PROGRAMMER *pgm, const AVRPART *p) { AVRMEM *basemem = cp == pgm->cp_flash? avr_locate_flash(p): cp == pgm->cp_eeprom? avr_locate_eeprom(p): cp == pgm->cp_bootrow? avr_locate_bootrow(p): avr_locate_usersig(p); - if(!basemem || !avr_has_paged_access(pgm, basemem)) + if(!basemem || !avr_has_paged_access(pgm, p, basemem)) return LIBAVRDUDE_GENERAL_FAILURE; cp->size = basemem->size; @@ -377,6 +378,9 @@ int avr_flush_cache(const PROGRAMMER *pgm, const AVRPART *p) { bool chiperase = 0; // Count page changes and find a page that needs a clear bit set for(size_t i = 0; i < sizeof mems/sizeof*mems; i++) { + if(mems[i].mem && avr_mem_exclude(pgm, p, mems[i].mem)) // Zap mem if excluded combo + memset(mems+i, 0, sizeof *mems); + AVRMEM *mem = mems[i].mem; AVR_Cache *cp = mems[i].cp; if(!mem || !cp->cont) @@ -439,7 +443,7 @@ int avr_flush_cache(const PROGRAMMER *pgm, const AVRPART *p) { } } - if(!mem_is_user_type(mems[i].mem)) // Only force CE if unable to write to flash/EEPROM + if(!mem_is_usersig(mems[i].mem)) // CE does not erase usersig chiperase = 1; } @@ -461,7 +465,7 @@ int avr_flush_cache(const PROGRAMMER *pgm, const AVRPART *p) { AVR_Cache *cp = mems[i].cp; if(!mem) continue; - if(mem_is_user_type(mem)) // CE does not affect bootrow/userrow + if(mem_is_usersig(mem)) // CE does not affect usersig/userrow continue; for(int pgno = 0, n = 0; n < cp->size; pgno++, n += cp->page_size) @@ -477,7 +481,7 @@ int avr_flush_cache(const PROGRAMMER *pgm, const AVRPART *p) { AVR_Cache *cp = mems[i].cp; if(!mem) continue; - if(mem_is_user_type(mem)) // CE does not affect bootrow/userrow + if(mem_is_usersig(mem)) // CE does not affect usersig/userrow continue; for(int ird = 0, pgno = 0, n = 0; n < cp->size; pgno++, n += cp->page_size) { @@ -506,7 +510,7 @@ int avr_flush_cache(const PROGRAMMER *pgm, const AVRPART *p) { AVR_Cache *cp = mems[i].cp; if(!mem) continue; - if(mem_is_user_type(mem)) // CE does not affect bootrow/userrow + if(mem_is_usersig(mem)) // CE does not affect usersig/userrow continue; if(mems[i].isflash) { @@ -607,7 +611,7 @@ int avr_read_byte_cached(const PROGRAMMER *pgm, const AVRPART *p, const AVRMEM * unsigned long addr, unsigned char *value) { // Use pgm->read_byte() if not flash/EEPROM/bootrow/usersig or no paged access - if(!avr_has_paged_access(pgm, mem)) + if(!avr_has_paged_access(pgm, p, mem)) return fallback_read_byte(pgm, p, mem, addr, value); // If address is out of range synchronise cache and, if successful, pretend reading a zero @@ -651,7 +655,7 @@ int avr_write_byte_cached(const PROGRAMMER *pgm, const AVRPART *p, const AVRMEM unsigned long addr, unsigned char data) { // Use pgm->write_byte() if not flash/EEPROM/bootrow/usersig or no paged access - if(!avr_has_paged_access(pgm, mem)) + if(!avr_has_paged_access(pgm, p, mem)) return fallback_write_byte(pgm, p, mem, addr, data); // If address is out of range synchronise caches with device and return whether successful @@ -702,7 +706,7 @@ int avr_chip_erase_cached(const PROGRAMMER *pgm, const AVRPART *p) { AVRMEM *mem = mems[i].mem; AVR_Cache *cp = mems[i].cp; - if(!mem || !avr_has_paged_access(pgm, mem)) + if(!mem || !avr_has_paged_access(pgm, p, mem)) continue; if(!cp->cont) // Init cache if needed @@ -751,7 +755,7 @@ int avr_page_erase_cached(const PROGRAMMER *pgm, const AVRPART *p, const AVRMEM int addr = uaddr; - if(!avr_has_paged_access(pgm, mem) || addr < 0 || addr >= mem->size) + if(!avr_has_paged_access(pgm, p, mem) || addr < 0 || addr >= mem->size) return LIBAVRDUDE_GENERAL_FAILURE; if(mem->page_size == 1) { diff --git a/src/avrdude.1 b/src/avrdude.1 index f36918dd..29edd9f0 100644 --- a/src/avrdude.1 +++ b/src/avrdude.1 @@ -1677,18 +1677,22 @@ versions of the bootloader. .It Ar dryboot These two programmers emulate programming and accept the following parameters: .Bl -tag -offset indent -width indent -.It Ar xinit +.It Ar init Initialise memories with human-readable patterns. Flash memory will be randomly configured with respect to bootloader, data and code length. Patterns can best be seen with fixed-width font and the :I format by inspecting the generated hex file or by using, eg, -U flash:r:-:I. Patterns in flash memory are executable and represent benign AVR code, ie, no I/O memory access. Choose a fixed seed for reproducible results. +.It Ar init= +Shortcut for -x init -x seed= (see below) .It Ar random Initialise memories with random code and values. Flash memory will be randomly configured with respect to bootloader, data and code length. Random code in flash will be benign, that is, not accessing I/O memories, SRAM or flash. Choose a fixed seed for reproducible results. +.It Ar random= +Shortcut for -x random -x seed= .It Ar seed= Seed random number generator with ; the default is time(NULL). Setting this option with a fixed n > 0 will make the random choices @@ -2286,7 +2290,7 @@ Alternative location of the per-user configuration file if above file does not e Initialization file for the .Xr readline 3 library -.It Pa /doc/avrdude/avrdude.pdf +.It Pa /share/doc/avrdude/avrdude.pdf User manual .El .\" .Sh EXAMPLES diff --git a/src/avrdude.conf.in b/src/avrdude.conf.in index 02c29168..9d64a83a 100644 --- a/src/avrdude.conf.in +++ b/src/avrdude.conf.in @@ -33,8 +33,8 @@ avrdude_conf_version = "@AVRDUDE_FULL_VERSION@"; # buff = [, ... ] ; # pin number(s) # reset = ; # pin number # sck = ; # pin number -# sdo = ; # pin number -# sdi = ; # pin number +# sdo|pico = ; # pin number +# sdi|poci = ; # pin number # tck = ; # pin number # tdi = ; # pin number # tdo = ; # pin number @@ -111,15 +111,8 @@ avrdude_conf_version = "@AVRDUDE_FULL_VERSION@"; # n_boot_sections = ; # Number of boot sections # boot_section_size = ; # Size of (smallest) boot section, if any # hvupdi_variant = ; # numeric -1 (n/a) or 0..2 -# devicecode = ; # deprecated, use stk500_devcode # stk500_devcode = ; # numeric # avr910_devcode = ; # numeric -# has_jtag = ; # part has JTAG i/f (deprecated, use prog_modes) -# has_debugwire = ; # part has debugWire i/f (deprecated, use prog_modes) -# has_pdi = ; # part has PDI i/f (deprecated, use prog_modes) -# has_updi = ; # part has UPDI i/f (deprecated, use prog_modes) -# has_tpi = ; # part has TPI i/f (deprecated, use prog_modes) -# is_avr32 = ; # AVR32 part (deprecated, use prog_modes) # is_at90s1200 = ; # AT90S1200 part # signature = ; # signature bytes # usbpid = ; # DFU USB PID @@ -242,8 +235,6 @@ avrdude_conf_version = "@AVRDUDE_FULL_VERSION@"; # ; # # NOTES: -# * 'devicecode' is the device code used by the STK500 (see codes -# listed below) # * Not all memories will implement all instructions # * AVR Fuse bits and Lock bits are implemented as a type of memory # * Example memories are: @@ -313,7 +304,7 @@ avrdude_conf_version = "@AVRDUDE_FULL_VERSION@"; # # # The following are STK500 part device codes to use for the -# "devicecode" field of the part. These came from Atmel's software +# stk500_devcode field of the part. These came from Atmel's software # section avr061.zip which accompanies the application note # AVR061 available from: # @@ -1537,6 +1528,8 @@ programmer # avrispmkII prog_modes = PM_TPI | PM_ISP | PM_PDI; extra_features = HAS_VTARG_READ; connection_type = usb; + usbvid = 0x03eb; + usbpid = 0x2104; ; #------------------------------------------------------------ @@ -1714,6 +1707,8 @@ programmer # stk600 prog_modes = PM_TPI | PM_ISP | PM_PDI; extra_features = HAS_VTARG_ADJ | HAS_VTARG_READ | HAS_FOSC_ADJ | HAS_VAREF_ADJ; connection_type = usb; + usbvid = 0x03eb; + usbpid = 0x2106; ; #------------------------------------------------------------ @@ -1727,6 +1722,8 @@ programmer # stk600pp prog_modes = PM_HVPP; extra_features = HAS_VTARG_ADJ | HAS_VTARG_READ | HAS_FOSC_ADJ | HAS_VAREF_ADJ; connection_type = usb; + usbvid = 0x03eb; + usbpid = 0x2106; ; #------------------------------------------------------------ @@ -1740,6 +1737,8 @@ programmer # stk600hvsp prog_modes = PM_HVSP; extra_features = HAS_VTARG_ADJ | HAS_VTARG_READ | HAS_FOSC_ADJ | HAS_VAREF_ADJ; connection_type = usb; + usbvid = 0x03eb; + usbpid = 0x2106; ; #------------------------------------------------------------ @@ -1773,6 +1772,8 @@ programmer # ft245r type = "ftdi_syncbb"; prog_modes = PM_TPI | PM_ISP; connection_type = usb; + usbvid = 0x0403; + usbpid = 0x6001; reset = 4; # D4 sck = 0; # D0 sdo = 2; # D2 @@ -1810,6 +1811,8 @@ programmer # bwmega type = "ftdi_syncbb"; prog_modes = PM_TPI | PM_ISP; connection_type = usb; + usbvid = 0x0403; + usbpid = 0x6001; reset = 7; # RI sck = 6; # DCD sdo = 3; # CTS @@ -1833,6 +1836,8 @@ programmer # arduino-ft232r type = "ftdi_syncbb"; prog_modes = PM_TPI | PM_ISP; connection_type = usb; + usbvid = 0x0403; + usbpid = 0x6001; reset = 7; # RI X3(4) sck = 5; # DSR X3(2) sdo = 6; # DCD X3(3) @@ -1852,6 +1857,8 @@ programmer # tc2030 type = "ftdi_syncbb"; prog_modes = PM_TPI | PM_ISP; connection_type = usb; + usbvid = 0x0403; + usbpid = 0x6001; # FOR TPI devices: reset = 3; # CTS = D3 (wire to ~RESET) sck = 2; # RTS = D2 (wire to SCK) @@ -1876,6 +1883,8 @@ programmer # uncompatino type = "ftdi_syncbb"; prog_modes = PM_TPI | PM_ISP; connection_type = usb; + usbvid = 0x0403; + usbpid = 0x6001; reset = 7; # ri sck = 5; # dsr sdo = 6; # dcd @@ -1908,6 +1917,8 @@ programmer # ttl232r type = "ftdi_syncbb"; prog_modes = PM_TPI | PM_ISP; connection_type = usb; + usbvid = 0x0403; + usbpid = 0x6001; reset = 0; # txd sck = 1; # rxd sdo = 3; # cts @@ -2280,6 +2291,8 @@ programmer # jtagmkII extra_features = HAS_VTARG_READ; connection_type = usb; baudrate = 19200; # default is 19200 + usbvid = 0x03eb; + usbpid = 0x2103; ; #------------------------------------------------------------ @@ -2315,6 +2328,8 @@ programmer # jtag2isp extra_features = HAS_VTARG_READ; connection_type = usb; baudrate = 115200; + usbvid = 0x03eb; + usbpid = 0x2103; ; #------------------------------------------------------------ @@ -2331,6 +2346,8 @@ programmer # jtag2dw extra_features = HAS_VTARG_READ; connection_type = usb; baudrate = 115200; + usbvid = 0x03eb; + usbpid = 0x2103; ; #------------------------------------------------------------ @@ -2347,6 +2364,8 @@ programmer # jtagmkII_avr32 extra_features = HAS_VTARG_READ; connection_type = usb; baudrate = 115200; + usbvid = 0x03eb; + usbpid = 0x2103; ; #------------------------------------------------------------ @@ -2363,6 +2382,8 @@ programmer # jtag2pdi extra_features = HAS_VTARG_READ; connection_type = usb; baudrate = 115200; + usbvid = 0x03eb; + usbpid = 0x2103; ; #------------------------------------------------------------ @@ -2381,6 +2402,8 @@ programmer # dragon_jtag extra_features = HAS_VTARG_READ; connection_type = usb; baudrate = 115200; + usbvid = 0x03eb; + usbpid = 0x2107; ; #------------------------------------------------------------ @@ -2397,6 +2420,8 @@ programmer # dragon_isp extra_features = HAS_VTARG_READ; connection_type = usb; baudrate = 115200; + usbvid = 0x03eb; + usbpid = 0x2107; ; #------------------------------------------------------------ @@ -2413,6 +2438,8 @@ programmer # dragon_pp extra_features = HAS_VTARG_READ; connection_type = usb; baudrate = 115200; + usbvid = 0x03eb; + usbpid = 0x2107; ; #------------------------------------------------------------ @@ -2429,6 +2456,8 @@ programmer # dragon_hvsp extra_features = HAS_VTARG_READ; connection_type = usb; baudrate = 115200; + usbvid = 0x03eb; + usbpid = 0x2107; ; #------------------------------------------------------------ @@ -2445,6 +2474,8 @@ programmer # dragon_dw extra_features = HAS_VTARG_READ; connection_type = usb; baudrate = 115200; + usbvid = 0x03eb; + usbpid = 0x2107; ; #------------------------------------------------------------ @@ -2461,6 +2492,8 @@ programmer # dragon_pdi extra_features = HAS_VTARG_READ; connection_type = usb; baudrate = 115200; + usbvid = 0x03eb; + usbpid = 0x2107; ; #------------------------------------------------------------ @@ -2488,6 +2521,7 @@ programmer # jtag3 prog_modes = PM_JTAG | PM_XMEGAJTAG | PM_AVR32JTAG; extra_features = HAS_VTARG_READ; connection_type = usb; + usbvid = 0x03eb; usbpid = 0x2110, 0x2140; ; @@ -2502,6 +2536,7 @@ programmer # jtag3pdi prog_modes = PM_PDI; extra_features = HAS_VTARG_READ; connection_type = usb; + usbvid = 0x03eb; usbpid = 0x2110, 0x2140; ; @@ -2516,6 +2551,7 @@ programmer # jtag3updi prog_modes = PM_UPDI; extra_features = HAS_VTARG_READ; connection_type = usb; + usbvid = 0x03eb; usbpid = 0x2110, 0x2140; hvupdi_support = 1; ; @@ -2531,6 +2567,7 @@ programmer # jtag3dw prog_modes = PM_debugWIRE; extra_features = HAS_VTARG_READ; connection_type = usb; + usbvid = 0x03eb; usbpid = 0x2110, 0x2140; ; @@ -2545,6 +2582,7 @@ programmer # jtag3isp prog_modes = PM_ISP; extra_features = HAS_VTARG_READ; connection_type = usb; + usbvid = 0x03eb; usbpid = 0x2110, 0x2140; ; @@ -2570,6 +2608,7 @@ programmer # xplainedpro prog_modes = PM_JTAG | PM_XMEGAJTAG | PM_AVR32JTAG; extra_features = HAS_VTARG_READ; connection_type = usb; + usbvid = 0x03eb; usbpid = 0x2111; ; @@ -2584,6 +2623,7 @@ programmer # xplainedpro_pdi prog_modes = PM_PDI; extra_features = HAS_VTARG_READ; connection_type = usb; + usbvid = 0x03eb; usbpid = 0x2111; hvupdi_support = 1; ; @@ -2599,6 +2639,7 @@ programmer # xplainedpro_updi prog_modes = PM_UPDI; extra_features = HAS_VTARG_READ; connection_type = usb; + usbvid = 0x03eb; usbpid = 0x2111; hvupdi_support = 1; ; @@ -2631,6 +2672,7 @@ programmer # xplainedmini prog_modes = PM_ISP; extra_features = HAS_SUFFER | HAS_VTARG_SWITCH; connection_type = usb; + usbvid = 0x03eb; usbpid = 0x2145; ; @@ -2650,6 +2692,7 @@ programmer # xplainedmini_dw prog_modes = PM_debugWIRE; extra_features = HAS_SUFFER | HAS_VTARG_SWITCH; connection_type = usb; + usbvid = 0x03eb; usbpid = 0x2145; ; @@ -2667,6 +2710,7 @@ programmer # xplainedmini_updi prog_modes = PM_UPDI; extra_features = HAS_SUFFER | HAS_VTARG_SWITCH; connection_type = usb; + usbvid = 0x03eb; usbpid = 0x2145; hvupdi_support = 1; ; @@ -2681,6 +2725,7 @@ programmer # xplainedmini_tpi type = "jtagice3_tpi"; prog_modes = PM_TPI; connection_type = usb; + usbvid = 0x03eb; usbpid = 0x2145; ; @@ -2709,6 +2754,7 @@ programmer # atmelice prog_modes = PM_JTAG | PM_XMEGAJTAG | PM_AVR32JTAG; extra_features = HAS_VTARG_READ; connection_type = usb; + usbvid = 0x03eb; usbpid = 0x2141; ; @@ -2723,6 +2769,7 @@ programmer # atmelice_pdi prog_modes = PM_PDI; extra_features = HAS_VTARG_READ; connection_type = usb; + usbvid = 0x03eb; usbpid = 0x2141; ; @@ -2737,6 +2784,7 @@ programmer # atmelice_updi prog_modes = PM_UPDI; extra_features = HAS_VTARG_READ; connection_type = usb; + usbvid = 0x03eb; usbpid = 0x2141; hvupdi_support = 1; ; @@ -2752,6 +2800,7 @@ programmer # atmelice_dw prog_modes = PM_debugWIRE; extra_features = HAS_VTARG_READ; connection_type = usb; + usbvid = 0x03eb; usbpid = 0x2141; ; @@ -2766,6 +2815,7 @@ programmer # atmelice_isp prog_modes = PM_ISP; extra_features = HAS_VTARG_READ; connection_type = usb; + usbvid = 0x03eb; usbpid = 0x2141; ; @@ -2780,6 +2830,7 @@ programmer # atmelice_tpi prog_modes = PM_TPI; extra_features = HAS_VTARG_READ; connection_type = usb; + usbvid = 0x03eb; usbpid = 0x2141; ; @@ -2813,6 +2864,7 @@ programmer # powerdebugger prog_modes = PM_JTAG | PM_XMEGAJTAG | PM_AVR32JTAG; extra_features = HAS_VTARG_ADJ | HAS_VTARG_READ; connection_type = usb; + usbvid = 0x03eb; usbpid = 0x2144; ; @@ -2827,6 +2879,7 @@ programmer # powerdebugger_pdi prog_modes = PM_PDI; extra_features = HAS_VTARG_ADJ | HAS_VTARG_READ; connection_type = usb; + usbvid = 0x03eb; usbpid = 0x2144; ; @@ -2841,6 +2894,7 @@ programmer # powerdebugger_updi prog_modes = PM_UPDI; extra_features = HAS_VTARG_ADJ | HAS_VTARG_READ; connection_type = usb; + usbvid = 0x03eb; usbpid = 0x2144; hvupdi_support = 0, 1; ; @@ -2856,6 +2910,7 @@ programmer # powerdebugger_dw prog_modes = PM_debugWIRE; extra_features = HAS_VTARG_ADJ | HAS_VTARG_READ; connection_type = usb; + usbvid = 0x03eb; usbpid = 0x2144; ; @@ -2870,6 +2925,7 @@ programmer # powerdebugger_isp prog_modes = PM_ISP; extra_features = HAS_VTARG_ADJ | HAS_VTARG_READ; connection_type = usb; + usbvid = 0x03eb; usbpid = 0x2144; ; @@ -2884,6 +2940,7 @@ programmer # powerdebugger_tpi prog_modes = PM_TPI; extra_features = HAS_VTARG_ADJ | HAS_VTARG_READ; connection_type = usb; + usbvid = 0x03eb; usbpid = 0x2144; ; @@ -2917,7 +2974,7 @@ programmer # powerdebugger_tpi # 4 TDO DATA UPDI SDI # 5 TCK SCK # 6 RST SCK dW RST -# 7 TDI SDI TX (target) +# 7 TDI SDO TX (target) # 8 TMS RX (target) # # * The PICkit4 can also be used as a USB to UART @@ -2930,6 +2987,7 @@ programmer # pickit4 prog_modes = PM_JTAG | PM_XMEGAJTAG; extra_features = HAS_VTARG_READ; connection_type = usb; + usbvid = 0x03eb; usbpid = 0x2177, 0x2178, 0x2179; ; @@ -2944,6 +3002,7 @@ programmer # pickit4_updi prog_modes = PM_UPDI; extra_features = HAS_VTARG_READ; connection_type = usb; + usbvid = 0x03eb; usbpid = 0x2177, 0x2178, 0x2179; hvupdi_support = 0, 1, 2; ; @@ -2959,6 +3018,7 @@ programmer # pickit4_pdi prog_modes = PM_PDI; extra_features = HAS_VTARG_READ; connection_type = usb; + usbvid = 0x03eb; usbpid = 0x2177, 0x2178, 0x2179; ; @@ -2976,6 +3036,7 @@ programmer # pickit4_isp prog_modes = PM_ISP; extra_features = HAS_VTARG_READ; connection_type = usb; + usbvid = 0x03eb; usbpid = 0x2177, 0x2178, 0x2179; ; @@ -2990,6 +3051,7 @@ programmer # pickit4_tpi prog_modes = PM_TPI; extra_features = HAS_VTARG_READ; connection_type = usb; + usbvid = 0x03eb; usbpid = 0x2177, 0x2178, 0x2179; ; @@ -3023,7 +3085,7 @@ programmer # pickit4_tpi # 4 TDO DATA UPDI SDI # 5 TCK SCK # 6 RST SCK dW RST -# 7 TDI SDI TX (target) +# 7 TDI SDO TX (target) # 8 TMS RX (target) # # * The MPLAB SNAP can also be used as a USB to UART @@ -3036,6 +3098,7 @@ programmer # snap prog_modes = PM_JTAG | PM_XMEGAJTAG; extra_features = HAS_VTARG_READ; connection_type = usb; + usbvid = 0x03eb; usbpid = 0x2180, 0x217f, 0x2181; ; @@ -3054,6 +3117,7 @@ programmer # snap_updi prog_modes = PM_UPDI; extra_features = HAS_VTARG_READ; connection_type = usb; + usbvid = 0x03eb; usbpid = 0x2180, 0x217f, 0x2181; hvupdi_support = 1; ; @@ -3069,6 +3133,7 @@ programmer # snap_pdi prog_modes = PM_PDI; extra_features = HAS_VTARG_READ; connection_type = usb; + usbvid = 0x03eb; usbpid = 0x2180, 0x217f, 0x2181; ; @@ -3086,6 +3151,7 @@ programmer # snap_isp prog_modes = PM_ISP; extra_features = HAS_VTARG_READ; connection_type = usb; + usbvid = 0x03eb; usbpid = 0x2180, 0x217f, 0x2181; ; @@ -3100,6 +3166,7 @@ programmer # snap_tpi prog_modes = PM_TPI; extra_features = HAS_VTARG_READ; connection_type = usb; + usbvid = 0x03eb; usbpid = 0x2180, 0x217f, 0x2181; ; @@ -3121,6 +3188,7 @@ programmer # pkobn_updi prog_modes = PM_UPDI; extra_features = HAS_VTARG_ADJ | HAS_VTARG_READ; connection_type = usb; + usbvid = 0x03eb; usbpid = 0x2175; hvupdi_support = 1; ; @@ -3163,6 +3231,8 @@ programmer # pickit2 type = "pickit2"; prog_modes = PM_ISP; connection_type = usb; + usbvid = 0x04d8; + usbpid = 0x0033; ; #------------------------------------------------------------ @@ -3180,6 +3250,7 @@ programmer # flip1 type = "flip1"; prog_modes = PM_SPM; connection_type = usb; + usbvid = 0x03eb; ; #------------------------------------------------------------ @@ -3196,6 +3267,7 @@ programmer # flip2 type = "flip2"; prog_modes = PM_SPM; connection_type = usb; + usbvid = 0x03eb; ; #------------------------------------------------------------ @@ -4033,6 +4105,10 @@ part parent "t11" # t12 write = "1010.1100--1111.1ii1--xxxx.xxxx--xxxx.xxxx"; ; + memory "prodsig" + read = "0 0 1 1 a0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 a4 a3 a2 a1 o o o o o o o o"; + ; + memory "signature" read = "0011.0000--xxxx.xxxx--0000.00aa--oooo.oooo"; ; @@ -4040,6 +4116,10 @@ part parent "t11" # t12 memory "calibration" read = "0011.1000--xxxx.xxxx--0000.0000--oooo.oooo"; ; + + memory "sernum" + read = "0 0 1 1 a0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 a4 a3 a2 a1 o o o o o o o o"; + ; ; #------------------------------------------------------------ @@ -4119,6 +4199,10 @@ part parent "t11" # t15 write = "1010.1100--1111.1ii1--xxxx.xxxx--xxxx.xxxx"; ; + memory "prodsig" + read = "0 0 1 1 a0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 a4 a3 a2 a1 o o o o o o o o"; + ; + memory "signature" read = "0011.0000--xxxx.xxxx--0000.00aa--oooo.oooo"; ; @@ -4126,6 +4210,10 @@ part parent "t11" # t15 memory "calibration" read = "0011.1000--xxxx.xxxx--0000.0000--oooo.oooo"; ; + + memory "sernum" + read = "0 0 1 1 a0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 a4 a3 a2 a1 o o o o o o o o"; + ; ; #------------------------------------------------------------ diff --git a/src/avrdude.spec.in b/src/avrdude.spec.in index b1e72e3d..0514345a 100644 --- a/src/avrdude.spec.in +++ b/src/avrdude.spec.in @@ -86,7 +86,6 @@ fi %doc %{_infodir}/*info* %doc doc/avrdude-html/*.html %doc doc/TODO -%doc doc/avrdude.ps %doc doc/avrdude.pdf %endif diff --git a/src/avrpart.c b/src/avrpart.c index 2bf03385..dea8c888 100644 --- a/src/avrpart.c +++ b/src/avrpart.c @@ -805,36 +805,33 @@ int avr_set_config_value(const PROGRAMMER *pgm, const AVRPART *p, const char *cn } -static char *print_num(const char *fmt, int n) { - return mmt_sprintf(n<10? "%d": fmt, n); +static const char *print_num(const char *fmt, int n) { + return str_ccprintf(n<10? "%d": fmt, n); } static int num_len(const char *fmt, int n) { - char *p = print_num(fmt, n); - int ret = strlen(p); - mmt_free(p); - - return ret; + return strlen(print_num(fmt, n)); } -void avr_mem_display(FILE *f, const AVRPART *p, const char *prefix) { +void avr_mem_display(FILE *f, const PROGRAMMER *pgm, const AVRPART *p, const char *prefix) { const char *table_colum[] = {"Memory", "Size", "Pg size", "Offset"}; const char *table_padding = "-------------------------------"; const int memory_col = 0, offset_col = 3; int m_char_max[4]; + AVRMEM *m; for(int i = 0; i < 4; i++) m_char_max[i] = strlen(table_colum[i]); for (LNODEID ln=lfirst(p->mem); ln; ln=lnext(ln)) { - AVRMEM *m = ldata(ln); + if(avr_mem_exclude(pgm, p, (m = ldata(ln)))) + continue; + int m_size[] = {0, m->size, m->page_size, m->offset}; - // Mem desc/size/pgsize/offset string length - AVRMEM_ALIAS *a = avr_find_memalias(p, m); + // Max column widths for(int i = 0; i < 4; i++) { - int len = i == memory_col? - (int) (strlen(m->desc) + strlen(a? "/": "") + strlen(a? a->desc: "")): // desc + int len = i == memory_col? (int) strlen(avr_mem_name(p, m)): num_len(i == offset_col? "0x%04x": "%d", m_size[i]); // size/pgsize/offset if(m_char_max[i] < len) m_char_max[i] = len; @@ -871,30 +868,24 @@ void avr_mem_display(FILE *f, const AVRPART *p, const char *prefix) { } for (LNODEID ln=lfirst(p->mem); ln; ln=lnext(ln)) { - AVRMEM *m = ldata(ln); - - // Create mem desc string including alias if present - AVRMEM_ALIAS *a = avr_find_memalias(p, m); - char *m_desc_str = mmt_sprintf("%s%s%s", m->desc, a? "/": "", a? a->desc: ""); + if(avr_mem_exclude(pgm, p, (m = ldata(ln)))) + continue; // Print memory table content if(p->prog_modes & (PM_PDI | PM_UPDI)) { - char *m_offset = print_num("0x%04x", m->offset); fprintf(f, "%s%-*s %*d %*d %*s \n", prefix, - m_char_max[0], m_desc_str, + m_char_max[0], avr_mem_name(p, m), m_char_max[1], m->size, m_char_max[2], m->page_size, - m_char_max[3], m_offset); - mmt_free(m_offset); + m_char_max[3], print_num("0x%04x", m->offset)); } else { fprintf(f, "%s%-*s %*d %*d\n", prefix, - m_char_max[0], m_desc_str, + m_char_max[0], avr_mem_name(p, m), m_char_max[1], m->size, m_char_max[2], m->page_size); } - mmt_free(m_desc_str); } } @@ -1170,12 +1161,12 @@ void sort_avrparts(LISTID avrparts) } -void avr_display(FILE *f, const AVRPART *p, const char *prefix, int verbose) { +void avr_display(FILE *f, const PROGRAMMER *pgm, const AVRPART *p, const char *prefix, int verbose) { fprintf(f, "%sAVR part : %s\n", prefix, p->desc); fprintf(f, "%sProgramming modes : %s\n", prefix, str_prog_modes(p->prog_modes)); if(verbose > 1) { - avr_mem_display(f, p, prefix); + avr_mem_display(f, pgm, p, prefix); avr_variants_display(f, p, prefix); } } diff --git a/src/build-helpers/versioninfo.m4 b/src/build-helpers/versioninfo.m4 index 30e36d6e..1fa441ef 100644 --- a/src/build-helpers/versioninfo.m4 +++ b/src/build-helpers/versioninfo.m4 @@ -9,6 +9,8 @@ dnl This must be the same sequence as the versioninfo script writes. m4_pattern_forbid([versioninfo_items]) m4_define([versioninfo_items], [ [CMAKE_PROJECT_VERSION], + [CMAKE_LIBAVRDUDE_VERSION], + [CMAKE_LIBAVRDUDE_SOVERSION], [GIT_COMMIT_DATE], [GIT_COMMIT_HASH], [GIT_TAG_HASH] diff --git a/src/build-helpers/versioninfo.sh b/src/build-helpers/versioninfo.sh index 58ebc9c6..4ca2a95e 100755 --- a/src/build-helpers/versioninfo.sh +++ b/src/build-helpers/versioninfo.sh @@ -89,6 +89,36 @@ test -n "$PROJECT_VERSION" || \ ret_error "Cannot find project(...) in top-level avrdude 'CMakeLists.txt'" +# Parse libavrdude library version from CMakeLists.txt +tmp="$(${AWK-awk} ' +BEGIN { v=0; } +($1 == "set_target_properties(libavrdude") { v=1; } +(v == 1) && /^[[:space:]]+\)/ { v=0; } +(v == 1) && /^[[:space:]]+VERSION[[:space:]]+/ { version=$2; } +(v == 1) && /^[[:space:]]+SOVERSION[[:space:]]+/ { soversion=$2; } +END { print version; + print soversion; } +' < "$top_srcdir/CMakeLists.txt")" + + +# Extract the libavrdude VERSION +CMAKE_LIBAVRDUDE_VERSION="$(printf "%s\n" "$tmp" | { \ + read LIB_VERSION; read LIB_SOVERSION; \ + printf "%s\n" "$LIB_VERSION"; })" + +test -n "$CMAKE_LIBAVRDUDE_VERSION" || \ + ret_error "Cannot find library VERSION in library 'CMakeLists.txt'" + + +# Extract the libavrdude SOVERSION +CMAKE_LIBAVRDUDE_SOVERSION="$(printf "%s\n" "$tmp" | { \ + read LIB_VERSION; read LIB_SOVERSION; \ + printf "%s\n" "$LIB_SOVERSION"; })" + +test -n "$CMAKE_LIBAVRDUDE_SOVERSION" || \ + ret_error "Cannot find library SOVERSION in library 'CMakeLists.txt'" + + # If GIT_DIR is set, use it. If not, try "$top_srcdir/../.git". test -n "$GIT_DIR" || { \ GIT_DIR="$top_srcdir/../.git"; \ @@ -106,11 +136,13 @@ if test -d "$GIT_DIR" && ${GIT-git} --version > /dev/null 2>&1; then ret_error "$prog: Cannot run 'git log' for tag hash" # This must be the same sequence as versioninfo_items in configure.ac ret_ok "${PROJECT_VERSION}" \ + "${CMAKE_LIBAVRDUDE_VERSION}" "${CMAKE_LIBAVRDUDE_SOVERSION}" \ "${GIT_COMMIT_DATE}" "${GIT_COMMIT_HASH}" "${GIT_TAG_HASH}" else # This is a github release tarball or github snapshot tarball # Presume this is a release version, because who would build a # non-release version from a snapshot tarball? - ret_ok "${PROJECT_VERSION}" + ret_ok "${PROJECT_VERSION}" \ + "${CMAKE_LIBAVRDUDE_VERSION}" "${CMAKE_LIBAVRDUDE_SOVERSION}" fi diff --git a/src/config_gram.y b/src/config_gram.y index eae57dfd..d266516f 100644 --- a/src/config_gram.y +++ b/src/config_gram.y @@ -86,7 +86,6 @@ static int parse_cmdbits(OPCODE * op, int opnum); %token K_DEFAULT_SPI %token K_DEFAULT_LINUXGPIO %token K_HVUPDI_SUPPORT -%token K_DEVICECODE %token K_EEPROM %token K_ERRLED %token K_FLASH @@ -137,13 +136,7 @@ static int parse_cmdbits(OPCODE * op, int opnum); * MCUs. */ %token K_ENABLEPAGEPROGRAMMING /* ? yes for mega256*, mega406 */ -%token K_HAS_JTAG /* MCU has JTAG i/f. */ -%token K_HAS_DW /* MCU has debugWire i/f. */ -%token K_HAS_PDI /* MCU has PDI i/f rather than ISP (ATxmega). */ -%token K_HAS_UPDI /* MCU has UPDI i/f (AVR8X). */ -%token K_HAS_TPI /* MCU has TPI i/f rather than ISP (ATtiny4/5/9/10). */ %token K_IS_AT90S1200 /* chip is an AT90S1200 (needs special treatment) */ -%token K_IS_AVR32 /* chip is in the avr32 family */ %token K_FLASH_INSTR /* flash instructions */ %token K_EEPROM_INSTR /* EEPROM instructions */ @@ -681,13 +674,6 @@ part_parm : } } | - K_DEVICECODE TKN_EQUAL numexpr { - { - yyerror("devicecode is deprecated, will be removed in v8.0, use stk500_devcode instead"); - YYABORT; - } - } | - K_SIGNATURE TKN_EQUAL TKN_NUMBER TKN_NUMBER TKN_NUMBER { { current_part->signature[0] = $3->value.number; @@ -864,56 +850,6 @@ part_parm : free_tokens(2, $1, $3); } | - K_HAS_JTAG TKN_EQUAL numexpr - { - yywarning("has_jtag is deprecated, will be removed in v8.0, use prog_modes"); - if ($3->value.number == 1) - current_part->prog_modes |= PM_JTAG; - else if ($3->value.number == 0) - current_part->prog_modes &= ~(PM_JTAG | PM_JTAGmkI | PM_XMEGAJTAG | PM_AVR32JTAG); - free_token($3); - } | - - K_HAS_DW TKN_EQUAL numexpr - { - yywarning("has_debugwire is deprecated, will be removed in v8.0, use prog_modes"); - if ($3->value.number == 1) - current_part->prog_modes |= PM_debugWIRE; - else if ($3->value.number == 0) - current_part->prog_modes &= ~PM_debugWIRE; - free_token($3); - } | - - K_HAS_PDI TKN_EQUAL numexpr - { - yywarning("has_pdi is deprecated, will be removed in v8.0, use prog_modes"); - if ($3->value.number == 1) - current_part->prog_modes |= PM_PDI; - else if ($3->value.number == 0) - current_part->prog_modes &= ~PM_PDI; - free_token($3); - } | - - K_HAS_UPDI TKN_EQUAL numexpr - { - yywarning("has_updi is deprecated, will be removed in v8.0, use prog_modes"); - if ($3->value.number == 1) - current_part->prog_modes |= PM_UPDI; - else if ($3->value.number == 0) - current_part->prog_modes &= ~PM_UPDI; - free_token($3); - } | - - K_HAS_TPI TKN_EQUAL numexpr - { - yywarning("has_tpi is deprecated, will be removed in v8.0, use prog_modes"); - if ($3->value.number == 1) - current_part->prog_modes |= PM_TPI; - else if ($3->value.number == 0) - current_part->prog_modes &= ~PM_TPI; - free_token($3); - } | - K_IS_AT90S1200 TKN_EQUAL numexpr { if ($3->value.number == 1) @@ -929,16 +865,6 @@ part_parm : free_token($3); } | - K_IS_AVR32 TKN_EQUAL numexpr - { - yywarning("is_avr32 is deprecated, will be removed in v8.0, use prog_modes"); - if ($3->value.number == 1) - current_part->prog_modes |= PM_aWire; - else if ($3->value.number == 0) - current_part->prog_modes &= ~PM_aWire; - free_token($3); - } | - K_ALLOWFULLPAGEBITSTREAM TKN_EQUAL numexpr { if ($3->value.number == 1) diff --git a/src/configure.ac b/src/configure.ac index b1e3102c..2abf9219 100644 --- a/src/configure.ac +++ b/src/configure.ac @@ -32,9 +32,10 @@ dnl 2018-02-25 automake 1.16 dnl 2018-03-11 automake 1.16.1 install-sh symlink fix -dnl Change this definition if you want to change the dist tarball name -dnl pattern from avrdude-7.3 for releases and avrdude-7.3-${COMMIT_DATE} -dnl for snapshots. +dnl Define the dist tarball name as +dnl * avrdude-7.3 for releases +dnl * avrdude-7.3-${COMMIT_DATE} for snapshots +dnl just like CMakeLists.txt does. m4_define([versioninfo_AVRDUDE_PACKAGE_VERSION], m4_case(m4_defn([versioninfo_GIT_COMMIT_HASH]), m4_defn([versioninfo_GIT_TAG_HASH]), @@ -63,7 +64,13 @@ AM_INIT_AUTOMAKE([ AM_SILENT_RULES([yes]) - +dnl Set up the macro definitions for versioninfo_* which we hand to AC_INIT. +dnl +dnl Yes, it does work to expand the VERSIONINFO_SETUP macro *after* AC_INIT: +dnl The presence of VERSIONINFO_SETUP pulls in the definitions at the top. +dnl +dnl For details, see the build-helpers/versioninfo.{md,m4,mk,sh} files. +m4_pattern_forbid([VERSIONINFO_SETUP])dnl VERSIONINFO_SETUP() dnl Inform about the derived PACKAGE_VERSION @@ -85,6 +92,33 @@ AC_DEFINE_UNQUOTED([AVRDUDE_FULL_VERSION], ["$AVRDUDE_FULL_VERSION"], AC_SUBST([AVRDUDE_FULL_VERSION]) +# Define libavrdude libtool version from cmake libavrdude information +dnl +dnl This is a very simple consistency check. If this check ever fails, +dnl the library versioning policy and its technical implementation +dnl must be adapted. +m4_case(m4_defn([versioninfo_CMAKE_LIBAVRDUDE_SOVERSION])[.0.0], + m4_defn([versioninfo_CMAKE_LIBAVRDUDE_VERSION]), + [], + [m4_fatal([ +The cmake libavrdude VERSION should be SOVERSION.0.0 ("]m4_defn([versioninfo_CMAKE_LIBAVRDUDE_SOVERSION])[.0.0"), +but it is actually "]m4_defn([versioninfo_CMAKE_LIBAVRDUDE_VERSION])[". + +This is an internal error in the logic which transfers library version +information from the cmake buildsystem to the automake buildsystem. + +Please file a GitHub issue for avrdude and mention @ndim. + ])])dnl +dnl +AC_MSG_CHECKING([versioninfo derived libtool -version-info for libavrdude]) +libavrdude_lt_cur=$CMAKE_LIBAVRDUDE_SOVERSION +libavrdude_lt_rev=0 +libavrdude_lt_age=0 +AC_SUBST([LIBAVRDUDE_VERSION_INFO], + [${libavrdude_lt_cur}:${libavrdude_lt_rev}:${libavrdude_lt_age}]) +AC_MSG_RESULT([$LIBAVRDUDE_VERSION_INFO]) + + # Checks for programs. AC_PROG_CC AC_PROG_INSTALL @@ -93,13 +127,17 @@ AC_PROG_SED AC_PROG_YACC AC_PROG_LEX([noyywrap]) AM_PROG_AR + +m4_pattern_forbid([LT_INIT])dnl LT_INIT() -# If macro PKG_PROG_PKG_CONFIG is not available, Autoconf generates a misleading error message, -# so check for existence first, and otherwise provide helpful advice. +dnl If macro PKG_PROG_PKG_CONFIG is not available, Autoconf generates +dnl a misleading error message, so check for existence first, and +dnl otherwise provide helpful advice. m4_ifndef([PKG_PROG_PKG_CONFIG], [m4_fatal(m4_normalize([ Macro PKG_PROG_PKG_CONFIG is not available. It is usually defined in file pkg.m4 provided by package pkg-config.]))]) +m4_pattern_forbid([PKG_PROG_PKG_CONFIG])dnl PKG_PROG_PKG_CONFIG([0.23]) AH_TEMPLATE([HAVE_YYLEX_DESTROY], diff --git a/src/developer_opts.c b/src/developer_opts.c index 0330d361..707be90e 100644 --- a/src/developer_opts.c +++ b/src/developer_opts.c @@ -1381,8 +1381,9 @@ static void dev_pgm_strct(const PROGRAMMER *pgm, bool tsv, const PROGRAMMER *bas for(int i=0; ipin+i); const char *bstr = base? pins_to_str(base->pin+i): NULL; - if(!base || !str_eq(bstr, str)) - _pgmout_fmt(avr_pin_lcname(i), "%s", str); + const char *pinname = avr_pin_lcname(i); + if((!base || !str_eq(bstr, str)) && !str_eq(pinname, "")) + _pgmout_fmt(pinname, "%s", str); } pgmstr = dev_hvupdi_support_liststr(pgm); @@ -1413,9 +1414,54 @@ static void dev_pgm_strct(const PROGRAMMER *pgm, bool tsv, const PROGRAMMER *bas } -// -c /[dASsrtiBUPTIJWHQ] +typedef struct { + int vid, pid, ishid; + const char *ids; +} Dev_udev; + + +static Dev_udev *add_udev(Dev_udev *ud, int *uip, int vid, int pid, int ishid, const char *ids) { + for(int i = 0; i < *uip; i++) // Already entered? + if(ud[i].vid == vid && ud[i].pid == pid && ud[i].ishid == ishid && ud[i].ids == ids) + return ud; + if(*uip % 128 == 0) + ud = (Dev_udev *) mmt_realloc(ud, sizeof*ud*(*uip+128)); + + ud[*uip].vid = vid; + ud[*uip].pid = pid; + ud[*uip].ishid = ishid; + ud[*uip].ids = ids; + (*uip)++; + + return ud; +} + +static int udev_cmp_wout_ids(const Dev_udev *p1, const Dev_udev *p2) { + int diff; + if((diff = p1->vid - p2->vid)) + return diff; + if((diff = p1->pid - p2->pid)) + return diff; + return p1->ishid - p2->ishid; +} + +static int udev_cmp(const void *v1, const void *v2) { + const Dev_udev *p1 = v1, *p2 = v2; + int diff; + + if((diff = udev_cmp_wout_ids(p1, p2))) + return diff; + return strcmp(p1->ids, p2->ids); +} + +#include "flip1.h" +#include "flip2.h" +#include "jtag3.h" +#include "stk500v2.h" + +// -c /[duASsrtiBUPTIJWHQ] void dev_output_pgm_defs(char *pgmidcp) { - bool descs, astrc, strct, cmpst, raw, tsv, injct; + bool descs, astrc, strct, cmpst, raw, tsv, injct, udev; char *flags; int nprinted; PROGRAMMER *nullpgm = pgm_new(); @@ -1426,7 +1472,7 @@ void dev_output_pgm_defs(char *pgmidcp) { if(!flags && str_eq(pgmidcp, "*")) // Treat -c * as if it was -c */s flags = "s"; - if(!*flags || !strchr("dASsrtiBUPTIJWHQ", *flags)) { + if(!*flags || !strchr("duASsrtiBUPTIJWHQ", *flags)) { dev_info("Error: flags for developer option -c / not recognised\n"); dev_info( "Wildcard examples (these need protecting in the shell through quoting):\n" @@ -1436,6 +1482,7 @@ void dev_output_pgm_defs(char *pgmidcp) { " jtag?pdi matches jtag2pdi and jtag3pdi\n" "Flags (one or more of the characters below):\n" " d description of core programmer features\n" + " u show udev entry for programmer\n" " A show entries of avrdude.conf programmers with all values\n" " S show entries of avrdude.conf programmers with necessary values\n" " s show short entries of avrdude.conf programmers using parent\n" @@ -1465,9 +1512,13 @@ void dev_output_pgm_defs(char *pgmidcp) { raw = !!strchr(flags, 'r'); tsv = !!strchr(flags, 't'); injct = !!strchr(flags, 'i'); + udev = !!strchr(flags, 'u'); nprinted = dev_nprinted; + int ui = 0; + Dev_udev *udr = NULL; + LNODEID ln1, ln2; for(ln1=lfirst(programmers); ln1; ln1=lnext(ln1)) { PROGRAMMER *pgm = ldata(ln1); @@ -1480,6 +1531,7 @@ void dev_output_pgm_defs(char *pgmidcp) { } if(!matched) continue; + if(!prog_modes_in_flags(pgm->prog_modes, flags)) continue; @@ -1499,16 +1551,103 @@ void dev_output_pgm_defs(char *pgmidcp) { for(LNODEID idn=lfirst(pgm->id); idn; idn=lnext(idn)) { char *id = ldata(idn); int len = 19-strlen(id); - dev_info("%s '%s' =>%*s ['%s', '%s'], # %s %d\n", + dev_info("%s '%s' =>%*s ['%s', '%s', '%s'], # %s %d\n", tsv? ".desc": " ", id, len > 0? len: 0, "", + locate_programmer_type_id(pgm->initpgm), dev_prog_modes(pgm->prog_modes), pgm->desc, pgm->config_file, pgm->lineno ); } + if(udev && pgm->usbpid && (pgm->conntype == CONNTYPE_USB || is_serialadapter(pgm))) { + void (* pi)(PROGRAMMER *) = pgm->initpgm; + const char *ids = cache_string(str_ccpgmids(pgm->id)); + int usbvid = pgm->usbvid, ishid = + pi == jtag3_initpgm || pi == jtag3_pdi_initpgm || pi == jtag3_updi_initpgm || + pi == jtag3_dw_initpgm || pi == stk500v2_jtag3_initpgm || pi == jtag3_tpi_initpgm; + + if(!lfirst(pgm->usbpid)) { + if(pi == flip1_initpgm || pi == flip2_initpgm) { // Bootloaders, add possible part pids + for(LNODEID lp = lfirst(part_list); lp; lp = lnext(lp)) { + AVRPART *pt = ldata(lp); + if(pt->usbpid) + udr = add_udev(udr, &ui, usbvid, pt->usbpid, 0, ids); + } + } + } + + for(LNODEID pidn=lfirst(pgm->usbpid); pidn; pidn=lnext(pidn)) { + int pid = *(int *) ldata(pidn); + udr = add_udev(udr, &ui, usbvid, pid, ishid, ids); + + // Piggy back PIC Snap devices that can be switched to AVR mode + if(usbvid == USB_VENDOR_ATMEL && pid >= 0x217f && pid <= 0x2181) { + udr = add_udev(udr, &ui, USB_VENDOR_MICROCHIP, USB_DEVICE_SNAP_PIC_MODE, ishid, ids); + udr = add_udev(udr, &ui, USB_VENDOR_MICROCHIP, USB_DEVICE_SNAP_PIC_MODE_BL, ishid, ids); + } + // Piggy back PIC pickit4 devices that can be switched to AVR ones + if(usbvid == USB_VENDOR_ATMEL && pid >= 0x2177 && pid <= 0x2179) { + udr = add_udev(udr, &ui, USB_VENDOR_MICROCHIP, USB_DEVICE_PICKIT4_PIC_MODE, ishid, ids); + udr = add_udev(udr, &ui, USB_VENDOR_MICROCHIP, USB_DEVICE_PICKIT4_PIC_MODE_BL, ishid, ids); + } + // Piggy back old usbasp when new one is seen + if(usbvid == USBASP_SHARED_VID && pid == USBASP_SHARED_PID) + udr = add_udev(udr, &ui, USBASP_OLD_VID, USBASP_OLD_PID, ishid, ids); + } + } + if(raw) dev_pgm_raw(pgm); } + + int reboot = 0; + for(Dev_udev *u = udr; !reboot && u-udr < ui; u++) + reboot |= u->ishid; + + if(udev && ui) { + int all = str_eq(pgmidcp, "*"); + const char *var = all? "": str_asciiname((char *) str_ccprintf("-%s", pgmidcp)); + dev_info("1. Examine the suggested udev rule%s below; to install run:\n\n", str_plural(ui + udr[0].ishid)); + dev_info("%s -c \"%s/u\" | tail -n +%d | sudo tee /etc/udev/rules.d/55-%s%s.rules\n", + progname, pgmidcp, all? 9: 11, progname, var); + dev_info("sudo chmod 0644 /etc/udev/rules.d/55-%s%s.rules\n\n", progname, var); + dev_info("2. %s\n", reboot? "Reboot your computer": "Unplug any AVRDUDE USB programmers and plug them in again"); + dev_info("3. Enjoy user access to the USB programmer(s)\n\n"); + if(!all) + dev_info("Note: To install all udev rules known to AVRDUDE follow: %s -c \"*/u\" | more\n\n", + progname); + dev_info("# Generated from avrdude -c \"%s/u\"\n", pgmidcp); + if(ui > 3) + dev_info("\nACTION!=\"add|change\", GOTO=\"avrdude_end\"\n"); + qsort(udr, ui, sizeof *udr, udev_cmp); + char *prev_head = mmt_strdup(""); + for(Dev_udev *u = udr; u-udr < ui; u++) { + char head[1024] = {0}, *h = head; + strncpy(h, u->ids, sizeof head - 1), h += strlen(h); + for(Dev_udev *v = u+1; v-udr < ui; v++) { + if(udev_cmp_wout_ids(u, v)) + break; + if((int) (strlen(v->ids) + 3 + h-head) <= (int) sizeof head) { + strcpy(h, ", "), h += 2; + strcpy(h, v->ids), h += strlen(v->ids); + } + u = v; + } + if(!str_eq(prev_head, head)) { + dev_info("\n# %s\n", head); + mmt_free(prev_head); + prev_head = mmt_strdup(head); + } + dev_info("SUBSYSTEM==\"usb\", ATTRS{idVendor}==\"%04x\", ATTRS{idProduct}==\"%04x\", " + "MODE=\"0660\", TAG+=\"uaccess\"\n", u->vid, u->pid); + if(u->ishid) + dev_info("KERNEL==\"hidraw*\", SUBSYSTEM==\"hidraw\", ATTRS{idVendor}==\"%04x\", " + "ATTRS{idProduct}==\"%04x\", MODE=\"0660\", TAG+=\"uaccess\"\n", u->vid, u->pid); + } + mmt_free(prev_head); + if(ui > 3) + dev_info("\nLABEL=\"avrdude_end\"\n"); + } } diff --git a/src/dfu.c b/src/dfu.c index 34d47eea..0aea930b 100644 --- a/src/dfu.c +++ b/src/dfu.c @@ -413,6 +413,7 @@ char * get_usb_string(usb_dev_handle * dev_handle, int index) { result = usb_get_string_simple(dev_handle, index, buffer, sizeof(buffer)-1); if (result < 0) { + cx->usb_access_error = 1; pmsg_error("unable to read USB device string %d: %s\n", index, usb_strerror()); return NULL; } diff --git a/src/disasm.c b/src/disasm.c index c35e59f7..cb6a657f 100644 --- a/src/disasm.c +++ b/src/disasm.c @@ -256,9 +256,9 @@ static int tagfile_readline(char *line, int lineno, const char * const *isrnames // Allocate, copy, append a suffix (H, L, 0...8 or nothing), cleanup name and return static char *regname(const char *pre, const char *reg, int suf) { char *ret = - suf <= -1? str_sprintf("%s%s", pre, reg): - suf == 'h' || suf == 'l'? str_sprintf("%s%s%c", pre, reg, suf): - str_sprintf("%s%s%d", pre, reg, suf); + suf <= -1? mmt_sprintf("%s%s", pre, reg): + suf == 'h' || suf == 'l'? mmt_sprintf("%s%s%c", pre, reg, suf): + mmt_sprintf("%s%s%d", pre, reg, suf); return cleanup(ret); } @@ -556,10 +556,10 @@ static int process_string(const char *buf, int buflen, int pos, int offset) { str[i-pos] = 0; out = cfg_escape(str); mmt_free(str); - code = str_sprintf(".ascii %s", out); + code = mmt_sprintf(".ascii %s", out); } else { // Nul terminated string out = cfg_escape(buf + pos); - code = str_sprintf(".asciz %s", out); + code = mmt_sprintf(".asciz %s", out); i++; } diff --git a/src/doc/CMakeLists.txt b/src/doc/CMakeLists.txt index 9c8030c3..5831fdaf 100644 --- a/src/doc/CMakeLists.txt +++ b/src/doc/CMakeLists.txt @@ -110,18 +110,6 @@ add_custom_command( VERBATIM ) -add_custom_command( - OUTPUT avrdude.dvi - COMMAND ${MAKEINFO_EXECUTABLE} - --dvi - --Xopt=--quiet - --Xopt=--build-dir=dvi - -o avrdude.dvi - ${TEXINFOS} - DEPENDS ${TEXINFOS} ${GENERATED_TEXINFOS} - VERBATIM - ) - add_custom_command( OUTPUT avrdude.pdf COMMAND ${MAKEINFO_EXECUTABLE} @@ -134,18 +122,6 @@ add_custom_command( VERBATIM ) -add_custom_command( - OUTPUT avrdude.ps - COMMAND ${MAKEINFO_EXECUTABLE} - --ps - --Xopt=--quiet - --Xopt=--build-dir=ps - -o avrdude.ps - ${TEXINFOS} - DEPENDS ${TEXINFOS} ${GENERATED_TEXINFOS} - VERBATIM - ) - add_custom_command( OUTPUT avrdude-html/avrdude.html COMMAND ${TEXI2HTML_EXECUTABLE} @@ -163,9 +139,7 @@ add_custom_command( # ===================================== add_custom_target(info ALL DEPENDS avrdude.info) -add_custom_target(dvi ALL DEPENDS avrdude.dvi) add_custom_target(pdf ALL DEPENDS avrdude.pdf) -add_custom_target(ps ALL DEPENDS avrdude.ps) add_custom_target(html ALL DEPENDS avrdude-html/avrdude.html) # ===================================== @@ -173,7 +147,5 @@ add_custom_target(html ALL DEPENDS avrdude-html/avrdude.html) # ===================================== install(FILES "${CMAKE_CURRENT_BINARY_DIR}/avrdude.info" DESTINATION ${CMAKE_INSTALL_INFODIR}) -install(FILES "${CMAKE_CURRENT_BINARY_DIR}/avrdude.dvi" DESTINATION ${CMAKE_INSTALL_DOCDIR}) install(FILES "${CMAKE_CURRENT_BINARY_DIR}/avrdude.pdf" DESTINATION ${CMAKE_INSTALL_DOCDIR}) -install(FILES "${CMAKE_CURRENT_BINARY_DIR}/avrdude.ps" DESTINATION ${CMAKE_INSTALL_DOCDIR}) install(DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/avrdude-html" DESTINATION ${CMAKE_INSTALL_DOCDIR}) diff --git a/src/doc/Makefile.am b/src/doc/Makefile.am index 66b55dc7..ff0bfdb1 100644 --- a/src/doc/Makefile.am +++ b/src/doc/Makefile.am @@ -31,7 +31,7 @@ info_TEXINFOS = avrdude.texi EXTRA_DIST = \ parts_comments.txt -all-local: info html ps pdf +all-local: info html pdf html: avrdude-html/avrdude.html @@ -76,9 +76,8 @@ clean-local: install-data-local: install-docs -install-docs: html ps pdf +install-docs: html pdf $(mkinstalldirs) $(DOC_INST_DIR) - $(INSTALL_DATA) avrdude.ps $(DOC_INST_DIR)/avrdude.ps $(INSTALL_DATA) avrdude.pdf $(DOC_INST_DIR)/avrdude.pdf $(mkinstalldirs) $(DOC_INST_DIR)/avrdude-html @list=`echo avrdude-html/*.html`; \ diff --git a/src/doc/avrdude.texi b/src/doc/avrdude.texi index 08ea52ff..eb97eda8 100644 --- a/src/doc/avrdude.texi +++ b/src/doc/avrdude.texi @@ -137,7 +137,7 @@ entire memory of the chip from the contents of a file, while interactive mode is useful for exploring memory contents, modifying individual bytes of eeprom, programming fuse/lock bits, etc. -@cindex Programmers Supported +@cindex Programmers supported AVRDUDE supports the following basic programmer types: Atmel's STK500, Atmel's AVRISP and AVRISP mkII devices, @@ -361,7 +361,7 @@ below for Teensy specific options. @c @node History, , Introduction, Introduction @section History and Credits -@cindex History and Credits +@cindex History and credits AVRDUDE was written by Brian S. Dean under the name of AVRPROG to run on the FreeBSD Operating System. Brian renamed the software to be called @@ -392,7 +392,7 @@ Roth. @c @node Command Line Options, Terminal Mode Operation, Introduction, Top @chapter Command Line Options -@cindex Command Line Options +@cindex Command line options @menu * Option Descriptions:: @@ -407,7 +407,7 @@ Roth. @node Option Descriptions, Programmers Accepting Exitspec Parameter, Programmers Accepting Extended Parameters, Command Line Options @cindex Options (command-line) @section Option Descriptions -@cindex Option Descriptions +@cindex Option descriptions @noindent AVRDUDE is a command line tool, used as follows: @@ -442,7 +442,7 @@ there can be deviations from this list, particularly if programming is directly via a bootloader. Currently, the following MCU types are understood: -@cindex Device Support +@cindex Device support @multitable @columnfractions .15 .45 @include parts.texi @@ -522,7 +522,7 @@ combination. In reality there can be deviations from this list, particularly if programming is directly via a bootloader. Currently, the following programmer ids are understood and supported: -@cindex Programmer Support +@cindex Programmer support @multitable @columnfractions .3 .68 @include programmers.texi @@ -539,6 +539,7 @@ usbtiny's properties; for more information run @code{avrdude -c x/h}. @item -C @var{config-file} @cindex Option @code{-C} @var{config-file} +@cindex Configuration files Use the specified config file for configuration data. This file contains all programmer and part definitions that AVRDUDE knows about. If not specified, AVRDUDE looks for the configuration file in the following @@ -1136,13 +1137,13 @@ see the extended options of the chosen programmer. @c Node @c @node Programmers Accepting Exitspec Parameter, Programmers Accepting Extended Parameters, Option Descriptions, Command Line Options -@section Programmers Accepting Exitspec Parameter -@cindex Programmers Accepting Exitspec parameter +@section Programmers Accepting Exitspec Parameters +@cindex Programmers accepting exitspec parameters @table @code @cindex Option @code{-x} flip2 @cindex Option @code{-x} linuxspi -@cindex Option @code{-x} Parallel port programmers +@cindex Option @code{-x} parallel port programmers @item flip2 @itemx linuxspi @itemx Parallel port programmers @@ -1174,7 +1175,7 @@ start the application if @samp{noreset} is used, and this is the default behaviour for this bootloader. @end table -@cindex Option @code{-x} Parallel port programmers +@cindex Option @code{-x} parallel port programmers @item Parallel port programmers Parallel port based programmers have a few more options. @@ -1205,7 +1206,7 @@ This option will leave the 8 data pins on the parallel port inactive @c @node Programmers Accepting Extended Parameters, Example Command Line Invocations, Programmers Accepting Exitspec Parameter, Command Line Options @section Programmers Accepting Extended Parameters -@cindex Programmers Accepting Extended Parameters +@cindex Programmers accepting extended parameters @table @code @cindex Option @code{-x} dryboot @@ -1216,8 +1217,7 @@ This option will leave the 8 data pins on the parallel port inactive Both dryrun and dryboot programmers emulate programming and accept the following parameters: @table @code -@item @samp{xinit} - +@item @samp{init} Initialise memories with human-readable patterns. Flash memory will be randomly configured with respect to bootloader, data and code length. Patterns can best be seen with fixed-width font and the @code{:I} format @@ -1226,12 +1226,18 @@ flash:r:-:I}. Patterns in flash memory are executable and represent benign AVR code, ie, no I/O memory access. Choose a fixed seed for reproducible results. +@item @samp{init=} +Shortcut for @code{-x init -x seed=} (see below) + @item @samp{random} Initialise memories with random code and values. Flash memory will be randomly configured with respect to bootloader, data and code length. Random code in flash will be benign, that is, not accessing I/O memories, SRAM or flash. Choose a fixed seed for reproducible results. +@item @samp{random=} +Shortcut for @code{-x random -x seed=} + @item @samp{seed=} Seed random number generator with @var{n}; the default is @code{time(NULL)}. Setting this option with a fixed positive @var{n} will @@ -1819,7 +1825,7 @@ Show help menu and exit. @c @node Example Command Line Invocations, , Programmers Accepting Extended Parameters, Command Line Options @section Example Command Line Invocations -@cindex Example Command Line Invocations +@cindex Example Command line invocations AVRDUDE error messages, warnings and progress reports are generally written to stderr which can, in bash, be turned off by @code{2>/dev/null} @@ -2307,7 +2313,7 @@ avrdude done. Thank you. @c @node Terminal Mode Operation, Configuration Files, Command Line Options, Top @chapter Terminal Mode Operation -@cindex Terminal Mode Operation +@cindex Terminal mode operation AVRDUDE has an interactive mode called @var{terminal mode} that is enabled by the @option{-t} option. This mode allows one to enter @@ -2325,7 +2331,7 @@ commands can be recalled and edited. @node Terminal Mode Commands, Terminal Mode Examples, Terminal Mode Operation, Terminal Mode Operation @section Terminal Mode Commands -@cindex Terminal Mode Commands +@cindex Terminal mode commands In this mode, AVRDUDE only initializes communication with the MCU, and then awaits user commands on standard input. Commands and parameters may be @@ -3420,7 +3426,7 @@ avrdude done. Thank you. @c Node @c @node Configuration Files, Programmer Specific Information, Terminal Mode Operation, Top -@cindex Configuration Files +@cindex Configuration files @cindex @code{avrdude.conf} @chapter Configuration Files @@ -3462,7 +3468,7 @@ the executable. @c @node AVRDUDE Defaults, Programmer Definitions, Configuration Files, Configuration Files @section AVRDUDE Defaults -@cindex AVRDUDE Defaults +@cindex AVRDUDE defaults @table @code @@ -3519,43 +3525,44 @@ configuration file with @var{yes}. @node Programmer Definitions, Serial Adapter Definitions, AVRDUDE Defaults, Configuration Files @cindex @code{programmer} @section Programmer Definitions -@cindex Programmer Definitions +@cindex Programmer definitions @noindent The format of the programmer definition is as follows: @smallexample programmer - parent # optional parent - id = [, ... ] ; # are quoted strings - desc = ; # quoted string - type = ; # programmer type, quoted string - # list known types with -c ?type - prog_modes = PM_ @{| PM_@} # interfaces, e.g., PM_SPM|PM_PDI (1) + parent # optional parent + id = [, ... ]; # are quoted strings + desc = ; # quoted string + type = ; # programmer type, quoted string + # list known types with -c ?type + prog_modes = PM_ @{| PM_@} # interfaces, e.g., PM_SPM|PM_PDI (1) + is_serialadapter = # programmer is also a serialadapter extra_features = HAS_ @{| HAS_@} # extra features, e.g., HAS_SUFFER (2) connection_type = parallel | serial | usb | spi - baudrate = ; # baudrate for avr910-programmer - vcc = [, ... ] ; # pin number(s) (3) - buff = [, ... ] ; # pin number(s) - reset = ; # pin number - sck = ; # pin number - sdo = ; # pin number - sdi = ; # pin number - tck = ; # pin number - tdi = ; # pin number - tdo = ; # pin number - tms = ; # pin number - errled = ; # pin number - rdyled = ; # pin number - pgmled = ; # pin number - vfyled = ; # pin number - usbvid = ; # USB vendor ID - usbpid = [, ...] ; # USB product ID (4) - usbdev = ; # USB interface or other device info - usbvendor = ; # USB Vendor Name - usbproduct = ; # USB Product Name - usbsn = ; # USB Serial Number - hvupdi_support = [, , ... ] ; # UPDI HV Variants Support + baudrate = ; # baudrate for avr910-programmer + vcc = [, ... ]; # pin number(s) (3) + buff = [, ... ]; # pin number(s) + reset = ; # pin number + sck = ; # pin number + sdo|pico = ; # pin number + sdi|poci = ; # pin number + tck = ; # pin number + tdi = ; # pin number + tdo = ; # pin number + tms = ; # pin number + errled = ; # pin number + rdyled = ; # pin number + pgmled = ; # pin number + vfyled = ; # pin number + usbvid = ; # USB vendor ID + usbpid = [, ...]; # USB product ID (4) + usbdev = ; # USB interface or other device info + usbvendor = ; # USB Vendor Name + usbproduct = ; # USB Product Name + usbsn = ; # USB Serial Number + hvupdi_support = [, , ... ]; # UPDI HV Variants Support ; @end smallexample @@ -3642,7 +3649,7 @@ The following programmer types are currently implemented: @node Serial Adapter Definitions, Part Definitions, Programmer Definitions, Configuration Files @cindex @code{serialadapter} @section Serial Adapter Definitions -@cindex Serial Adapter Definitions +@cindex Serial adapter definitions @noindent The format of a serial adapter definition is as follows: @@ -3650,12 +3657,12 @@ The format of a serial adapter definition is as follows: @smallexample serialadapter parent # optional serialadapter or programmer parent - id = [, ... ] ; # are quoted strings - desc = ; # quoted string - baudrate = ; # optional default baudrate, eg, in .avrduderc - usbvid = ; # USB vendor ID - usbpid = [, ...] ; # list of USB product IDs - usbsn = ; # USB Serial Number in per-user .avrduderc + id = [, ... ]; # are quoted strings + desc = ; # quoted string + baudrate = ; # optional default baudrate, eg, in .avrduderc + usbvid = ; # USB vendor ID + usbpid = [, ...]; # list of USB product IDs + usbsn = ; # USB Serial Number in per-user .avrduderc ; @end smallexample @@ -3688,14 +3695,14 @@ utilised as a serialadapter. @node Part Definitions, Other Notes, Serial Adapter Definitions, Configuration Files @cindex @code{part} @section Part Definitions -@cindex Part Definitions +@cindex Part definitions @smallexample part - desc = ; # quoted string, the long part name, eg, "ATmega328p" - id = ; # quoted string, normally an abbreviated part name + desc = ; # quoted string, the long part name, eg, "ATmega328p" + id = ; # quoted string, normally an abbreviated part name variants = [, ...]; # quoted strings, each starts so ": ..." - family_id = ; # quoted string, e.g., "megaAVR" or "tinyAVR" + family_id = ; # quoted string, e.g., "megaAVR" or "tinyAVR" prog_modes = PM_ @{| PM_@} # interfaces, e.g., PM_SPM|PM_ISP|PM_HVPP|PM_debugWIRE mcuid = ; # unique id in 0..2039 for 8-bit AVRs archnum = ; # avr-gcc architecture number for the part @@ -3703,108 +3710,101 @@ part n_page_erase = ; # if set, number of pages erased during SPM erase n_boot_sections = ; # Number of boot sections boot_section_size = ; # Size of (smallest) boot section, if any - hvupdi_variant = ; # numeric -1 (n/a) or 0..2 - devicecode = ; # deprecated, use stk500_devcode - stk500_devcode = ; # numeric - avr910_devcode = ; # numeric - has_jtag = ; # part has JTAG i/f (deprecated, use prog_modes) - has_debugwire = ; # part has debugWire i/f (deprecated, use prog_modes) - has_pdi = ; # part has PDI i/f (deprecated, use prog_modes) - has_updi = ; # part has UPDI i/f (deprecated, use prog_modes) - has_tpi = ; # part has TPI i/f (deprecated, use prog_modes) - is_avr32 = ; # AVR32 part (deprecated, use prog_modes) - is_at90s1200 = ; # AT90S1200 part - signature = ; # signature bytes - usbpid = ; # DFU USB PID - chip_erase_delay = ; # microseconds - reset = dedicated | io ; - retry_pulse = reset | sck ; + hvupdi_variant = ; # numeric -1 (n/a) or 0..2 + stk500_devcode = ; # numeric + avr910_devcode = ; # numeric + is_at90s1200 = ; # AT90S1200 part + signature = ; # signature bytes + usbpid = ; # DFU USB PID + chip_erase_delay = ; # microseconds + reset = dedicated | io; + retry_pulse = reset | sck; # STK500 parameters (parallel programming IO lines) - pagel = ; # page load pin name in hex, e.g., 0xD7 - bs2 = ; # byte select 2 pin name in hex, e.g., 0xA0 - serial = ; # can use serial downloading - parallel = ; # can use parallel programming + pagel = ; # page load pin name in hex, e.g., 0xD7 + bs2 = ; # byte select 2 pin name in hex, e.g., 0xA0 + serial = ; # can use serial downloading + parallel = ; # can use parallel programming # STK500v2 parameters, to be taken from Atmel's ATDF files - timeout = ; - stabdelay = ; - cmdexedelay = ; - synchloops = ; - bytedelay = ; - pollvalue = ; - pollindex = ; - predelay = ; - postdelay = ; - pollmethod = ; - hvspcmdexedelay = ; + timeout = ; + stabdelay = ; + cmdexedelay = ; + synchloops = ; + bytedelay = ; + pollvalue = ; + pollindex = ; + predelay = ; + postdelay = ; + pollmethod = ; + hvspcmdexedelay = ; # STK500v2 HV programming parameters, from ATDFs - pp_controlstack = , , ... ; # PP only - hvsp_controlstack = , , ... ; # HVSP only - flash_instr = , , ; - eeprom_instr = , , ... ; - hventerstabdelay = ; - progmodedelay = ; # PP only - latchcycles = ; - togglevtg = ; - poweroffdelay = ; - resetdelayms = ; - resetdelayus = ; - hvleavestabdelay = ; - resetdelay = ; - synchcycles = ; # HVSP only - chiperasepulsewidth = ; # PP only - chiperasepolltimeout = ; - chiperasetime = ; # HVSP only - programfusepulsewidth = ; # PP only - programfusepolltimeout = ; - programlockpulsewidth = ; # PP only - programlockpolltimeout = ; + pp_controlstack = , , ...; # PP only + hvsp_controlstack = , , ...; # HVSP only + flash_instr = , , ; + eeprom_instr = , , ...; + hventerstabdelay = ; + progmodedelay = ; # PP only + latchcycles = ; + togglevtg = ; + poweroffdelay = ; + resetdelayms = ; + resetdelayus = ; + hvleavestabdelay = ; + resetdelay = ; + synchcycles = ; # HVSP only + chiperasepulsewidth = ; # PP only + chiperasepolltimeout = ; + chiperasetime = ; # HVSP only + programfusepulsewidth = ; # PP only + programfusepolltimeout = ; + programlockpulsewidth = ; # PP only + programlockpolltimeout = ; # debugWIRE and/or JTAG ICE mkII parameters, also from ATDF files - allowfullpagebitstream = ; - enablepageprogramming = ; - idr = ; # IO addr of IDR (OCD) reg - rampz = ; # IO addr of RAMPZ reg - spmcr = ; # mem addr of SPMC[S]R reg - eecr = ; # mem addr of EECR reg - eind = ; # mem addr of EIND reg - mcu_base = ; # MCU control block in ATxmega devices - nvm_base = ; # NVM controller in ATxmega devices - ocd_base = ; # OCD module in AVR8X/UPDI devices - syscfg_base = ; # Chip revision ID in AVR8X/UPDI devices - ocdrev = ; # JTAGICE3 parameter from ATDF files - pgm_enable = ; - chip_erase = ; + allowfullpagebitstream = ; + enablepageprogramming = ; + idr = ; # IO addr of IDR (OCD) reg + rampz = ; # IO addr of RAMPZ reg + spmcr = ; # mem addr of SPMC[S]R reg + eecr = ; # mem addr of EECR reg + eind = ; # mem addr of EIND reg + mcu_base = ; # MCU control block in ATxmega devices + nvm_base = ; # NVM controller in ATxmega devices + ocd_base = ; # OCD module in AVR8X/UPDI devices + syscfg_base = ; # Chip revision ID in AVR8X/UPDI devices + ocdrev = ; # JTAGICE3 parameter from ATDF files + pgm_enable = ; + chip_erase = ; # parameters for bootloaders - autobaud_sync = ; # autobaud detection byte, default 0x30 - factory_fcpu = ; # F_CPU in Hz on reset and factory-set fuses + autobaud_sync = ; # autobaud detection byte, default 0x30 + factory_fcpu = ; # F_CPU in Hz on reset and factory-set fuses memory - paged = ; # yes/no (flash of classic parts only) - offset = ; # memory offset - size = ; # bytes - page_size = ; # bytes - num_pages = ; # numeric - initval = ; # factory setting of fuses and lockbits - bitmask = ; # bits used (only in fuses and lockbits) - n_word_writes = ; # TPI only: if set, number of words to write - min_write_delay = ; # micro-seconds - max_write_delay = ; # micro-seconds - readback = ; # pair of byte values - readback_p1 = ; # byte value (first component) - readback_p2 = ; # byte value (second component) - pwroff_after_write = ; # yes/no - mode = ; # STK500 v2 file parameter from ATDF files - delay = ; # " - blocksize = ; # " - readsize = ; # " - read = ; - write = ; - read_lo = ; - read_hi = ; - write_lo = ; - write_hi = ; - loadpage_lo = ; - loadpage_hi = ; - writepage = ; + paged = ; # yes/no (flash of classic parts only) + offset = ; # memory offset + size = ; # bytes + page_size = ; # bytes + num_pages = ; # numeric + initval = ; # factory setting of fuses and lockbits + bitmask = ; # bits used (only in fuses and lockbits) + n_word_writes = ; # TPI only: if set, number of words to write + min_write_delay = ; # micro-seconds + max_write_delay = ; # micro-seconds + readback = ; # pair of byte values + readback_p1 = ; # byte value (first component) + readback_p2 = ; # byte value (second component) + pwroff_after_write = ; # yes/no + mode = ; # STK500 v2 file parameter from ATDF files + delay = ; # " + blocksize = ; # " + readsize = ; # " + read = ; + write = ; + read_lo = ; + read_hi = ; + write_lo = ; + write_hi = ; + loadpage_lo = ; + loadpage_hi = ; + writepage = ; ; ; @end smallexample @@ -3830,7 +3830,7 @@ arithemtic and bitwise operators. @c @node Parent Part, Instruction Format, Part Definitions, Part Definitions @subsection Parent Part -@cindex Parent Part +@cindex Parent part @noindent Parts can also inherit parameters from previously defined parts using @@ -3852,7 +3852,7 @@ Example format for part inheritance: @smallexample part parent # String identifying parent - id = ; # Id string for new part + id = ; # Id string for new part ; @end smallexample @@ -3862,7 +3862,7 @@ Example format for part inheritance: @c @node Instruction Format, , Parent Part, Part Definitions @subsection Instruction Format -@cindex Instruction Format +@cindex Instruction format @noindent Instruction formats are specified as a comma separated list of string @@ -3939,12 +3939,12 @@ Examples: @c @node Other Notes, , Part Definitions, Configuration Files @section Other Notes -@cindex Other Notes +@cindex Other notes @itemize @bullet @item -The @code{devicecode} parameter is the device code used by the STK500 +The @code{stk500_devcode} parameter is the device code used by the STK500 and is obtained from the software section (@code{avr061.zip}) of Atmel's AVR061 application note available from @url{http://www.atmel.com/dyn/resources/prod_documents/doc2525.pdf}. @@ -3995,8 +3995,8 @@ Reading fuse and lock bits is fully supported. @c Node @c @node Programmer Specific Information, Platform Dependent Information, Configuration Files, Top -@chapter Programmer Specific Information -@cindex Programmer Specific Information +@chapter Programmer-Specific Information +@cindex Programmer-specific information @menu * Atmel STK600:: @@ -4108,7 +4108,7 @@ least 4.5 V in order to work. This can be done using @c @node DFU Bootloader Using FLIP Version 1, SerialUPDI Programmer , Atmel STK600, Programmer Specific Information @section DFU Bootloader Using FLIP Version 1 -@cindex DFU Bootloader Using FLIP Version 1 +@cindex DFU Bootloader using FLIP version 1 Bootloaders using the FLIP protocol version 1 experience some very specific behaviour. @@ -4138,7 +4138,7 @@ versions of the bootloader. @node SerialUPDI Programmer, Programmer LED Management, DFU Bootloader Using FLIP Version 1, Programmer Specific Information @cindex SerialUPDI @section SerialUPDI Programmer -@cindex SerialUPDI Programmer +@cindex SerialUPDI programmer SerialUPDI programmer can be used for programming UPDI-only devices using very simple serial connection. @@ -4231,7 +4231,8 @@ analysis of UPDI protocol quirks easier. @c @node Programmer LED Management, , SerialUPDI Programmer, Programmer Specific Information @section Programmer LED Management -@cindex Programmer LED Management +@cindex Programmer LED management +@cindex LED management Some hardware programmers have LEDs, and the firmware controls them fully without AVRDUDE having a way to influence their LED states. Other @@ -4286,6 +4287,7 @@ Other combinations should not show after exit. * Unix Installation:: * Unix Configuration Files:: * Unix Port Names:: +* Unix USB Permissions:: * Unix Documentation:: @end menu @@ -4294,7 +4296,8 @@ Other combinations should not show after exit. @c @node Unix Installation, Unix Configuration Files, Unix, Unix @subsection Unix Installation -@cindex Unix Installation +@cindex Unix installation +@cindex Installation @noindent To build and install from the source tarball on Unix like systems: @@ -4332,7 +4335,8 @@ $ make install @c @node FreeBSD Installation, Linux Installation, Unix Installation, Unix Installation @subsubsection FreeBSD Installation -@cindex FreeBSD Installation +@cindex FreeBSD installation +@cindex Installation @noindent AVRDUDE is installed via the FreeBSD Ports Tree as follows: @@ -4360,7 +4364,8 @@ obtained. @c @node Linux Installation, , FreeBSD Installation, Unix Installation @subsubsection Linux Installation -@cindex Linux Installation +@cindex Linux installation +@cindex Installation @noindent On rpm based Linux systems (such as RedHat, SUSE, Mandrake, etc.), you @@ -4380,10 +4385,11 @@ to system. The above example is specific to RedHat. @c @node Unix Configuration Files, Unix Port Names, Unix Installation, Unix @subsection Unix Configuration Files -@cindex Unix Configuration Files +@cindex Unix configuration files +@cindex Configuration files @noindent -When AVRDUDE is build using the default @option{--prefix} configure +When AVRDUDE is built using the default @option{--prefix} configure option, the default configuration file for a Unix system is located at @code{/usr/local/etc/avrdude.conf}. This can be overridden by using the @option{-C} command line option. Additionally, the user's home directory @@ -4400,7 +4406,8 @@ augment the system default configuration file. @c @node FreeBSD Configuration Files, Linux Configuration Files, Unix Configuration Files, Unix Configuration Files @subsubsection FreeBSD Configuration Files -@cindex FreeBSD Configuration Files +@cindex FreeBSD configuration files +@cindex Configuration files @noindent When AVRDUDE is installed using the FreeBSD ports system, the system @@ -4411,7 +4418,8 @@ configuration file is always @code{/usr/local/etc/avrdude.conf}. @c @node Linux Configuration Files, , FreeBSD Configuration Files, Unix Configuration Files @subsubsection Linux Configuration Files -@cindex Linux Configuration Files +@cindex Linux configuration files +@cindex Configuration files @noindent When AVRDUDE is installed using from an rpm package, the system @@ -4420,9 +4428,9 @@ configuration file will be always be @code{/etc/avrdude.conf}. @c @c Node @c -@node Unix Port Names, Unix Documentation, Unix Configuration Files, Unix +@node Unix Port Names, Unix USB Permissions, Unix Configuration Files, Unix @subsection Unix Port Names -@cindex Unix Port Names +@cindex Unix port names @noindent The parallel and serial port device file names are system specific. @@ -4457,12 +4465,158 @@ On Solaris systems, AVRDUDE uses the ecpp(7D) driver for accessing the parallel port and the asy(7D) driver for serial port access. +@c +@c Node +@c +@node Unix USB Permissions, Unix Port Names, Unix Documentation, Unix +@subsection Unix USB Permissions +@cindex Unix USB permissions +@cindex USB permissions + +In most cases the kernel driver initializes a plug-and-play device to be +owned by user @code{root} and group @code{root} with only r/w permission +for the user @code{root} rendering the device inaccessible to regular +users. Whilst users can run AVRDUDE sessions as root this is definitely +@emph{not good practice}. Giving USB plug-and-play devices the correct +permissions is much better. USB AVR programmers are normally identified by +a two-byte hexadecimal vendor ID and a two-byte hexadecimal product id. +Both are typically used to identify the device that needs new permissions. + +@menu +* FreeBSD USB Permissions:: +* Linux USB Permissions:: +@end menu + +@c +@c Node +@c +@node FreeBSD USB Permissions, Linux USB Permissions, Unix USB Permissions, Unix USB Permissions +@subsubsection FreeBSD USB Permissions +@cindex FreeBSD USB permissions +@cindex USB permissions + +In FreeBSD a so-called @code{devd} config files in +@code{/usr/local/etc/devd} serve to modify permissions of plugged-in USB +devices. Here is an example how Atmel's JTAGICE3 programmer (product ID +0x2110 or 0x2140) by Atmel (vendor ID 0x0eb) can be given appropriate +permissions using a file @code{jtagice3.conf}: + +@smallexample +@cartouche + +notify 100 @{ + match "system" "USB"; + match "subsystem" "DEVICE"; + match "type" "ATTACH"; + match "vendor" "0x03eb"; + match "product" "(0x2110|0x2140)"; + action "chmod 660 /dev/$cdev"; + action "chgrp yourgroup /dev/$cdev"; +@}; + +@end cartouche +@end smallexample + +@noindent @code{yourgroup} would be a group that the user(s) should be +member of who wish to have access to the programmer. + +@c +@c Node +@c +@node Linux USB Permissions, , FreeBSD USB Permissions, Unix USB Permissions +@subsubsection Linux USB Permissions +@cindex Linux USB permissions +@cindex USB permissions + +Linux has a special userspace @code{/dev} device manager called udev that +deals with, amongst other things, plug-and-play USB devices. It is +recommended to specify so-called udev rules to define access permissions +for these devices instead. These rules typically reside in a file with the +name @var{nn}@code{-}@var{descriptive-name}@code{.rules} in the directory +@code{/etc/udev/rules.d}. Here, @var{nn} is a two-digit number that +determines the lexical order in which the udev rule files are processed. +Rules processed later can overwrite earlier rules, but it not recommended +to put user-generated rules higher than 60, as some of the actions they +require are processed by higher-level system rules. + +Here a typical udev rule for allowing an ordinary user access to the +plugged-in AVRISP mkII programmer (product ID 0x2104) by Atmel (vendor ID +0x0eb): + +@smallexample +@cartouche + +SUBSYSTEM=="usb", ATTRS@{idVendor@}=="03eb", ATTRS@{idProduct@}=="2104", \ + MODE="0660", TAG+="uaccess" + +@end cartouche +@end smallexample + +@noindent This furnishes the corresponding device node with @code{0660} +access permissions: this means r/w for the user @code{root} and any user +belonging to the group of the device, which the device driver might assign +to a different group than the default @code{root}. The key of the rule is +the attached @code{TAG} named @code{uaccess}, which has the effect that +the login daemon applies a dynamic user access control list to the device +node making the device usable for the currently logged-in user. When used +in anger, udev rules must appear on one line; above example was broken +into two lines so it fits into the example box. + +AVRDUDE's developer option @code{-c }@var{programmer}@code{/u} will show +above suggested udev rule for the named programmer. Wildcards are allowed: + +@smallexample +@cartouche + +$ avrdude -c jtag\*/u + +1. Examine the suggested udev rules below; to install run: + +avrdude -c "jtag*/u" | tail -n +11 | sudo tee /etc/udev/rules.d/55-avrdude-jtagX.rules +sudo chmod 0644 /etc/udev/rules.d/55-avrdude-jtagX.rules + +2. Unplug any AVRDUDE USB programmers and plug them in again +3. Enjoy user access to the USB programmer(s) + +Note: To install all udev rules known to AVRDUDE follow: avrdude -c "*/u" | more + +# Generated from avrdude -c "jtag*/u" + +ACTION!="add|change", GOTO="avrdude_end" + +# jtag2dw, jtag2fast, jtag2, jtag2isp, jtag2pdi, jtag2slow, jtagmkII, jtag2avr32 +SUBSYSTEM=="usb", ATTRS@{idVendor@}=="03eb", ATTRS@{idProduct@}=="2103", \ + MODE="0660", TAG+="uaccess" + +# jtag3, jtag3dw, jtag3isp, jtag3pdi, jtag3updi +SUBSYSTEM=="usb", ATTRS@{idVendor@}=="03eb", ATTRS@{idProduct@}=="2110", \ + MODE="0660", TAG+="uaccess" +KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS@{idVendor@}=="03eb", \ + ATTRS@{idProduct@}=="2110", MODE="0660", TAG+="uaccess" +SUBSYSTEM=="usb", ATTRS@{idVendor@}=="03eb", ATTRS@{idProduct@}=="2140", \ + MODE="0660", TAG+="uaccess" +KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS@{idVendor@}=="03eb", \ + ATTRS@{idProduct@}=="2140", MODE="0660", TAG+="uaccess" + +# jtagkey +SUBSYSTEM=="usb", ATTRS@{idVendor@}=="0403", ATTRS@{idProduct@}=="cff8", \ + MODE="0660", TAG+="uaccess" + +@end cartouche +@end smallexample + +@cindex USB permissions +@noindent Again, each rule must be written as one line: breaking up rules +into two lines was only done to fit AVRDUDE's output to the boxed display. +USB devices in HID mode require a second rule dealing with the +@code{hidraw} subsystem as seen above. + @c @c Node @c @node Unix Documentation, , Unix Port Names, Unix @subsection Unix Documentation -@cindex Unix Documentation +@cindex Unix documentation @noindent AVRDUDE installs a manual page as well as info, HTML and PDF @@ -4533,7 +4687,7 @@ compiler version that still supports MinGW builds, or use MinGW @c @node Windows Configuration Files, Windows Port Names, Windows Installation, Windows @subsection Windows Configuration Files -@cindex Windows Configuration Files +@cindex Windows configuration files @menu * Configuration file names:: @@ -4545,7 +4699,7 @@ compiler version that still supports MinGW builds, or use MinGW @c @node Configuration file names, Windows Configuration File Location, Windows Configuration Files, Windows Configuration Files @subsubsection Windows Configuration File Names -@cindex Windows Configuration File Names +@cindex Windows configuration file names @noindent AVRDUDE on Windows looks for a system configuration file name of @@ -4557,7 +4711,7 @@ AVRDUDE on Windows looks for a system configuration file name of @c @node Windows Configuration File Location, , Configuration file names, Windows Configuration Files @subsubsection Windows Configuration File Location -@cindex Windows Configuration File Location +@cindex Windows configuration file location @noindent AVRDUDE on Windows has a different way of searching for the system and @@ -4598,7 +4752,7 @@ The directories that are listed in the PATH environment variable. @c @node Windows Port Names, Windows Configuration Files, Windows @subsection Windows Port Names -@cindex Windows Port Names +@cindex Windows port names @menu * Serial Ports:: @@ -4610,7 +4764,7 @@ The directories that are listed in the PATH environment variable. @c @node Serial Ports, Parallel Ports, Windows Port Names, Windows Port Names @subsubsection Windows Serial Ports -@cindex Windows Serial Ports +@cindex Windows serial ports @noindent When you select a serial port (i.e. when using an STK500) use the @@ -4621,7 +4775,7 @@ Windows serial port device names such as: com1, com2, etc. @c @node Parallel Ports, , Serial Ports, Windows Port Names @subsubsection Windows Parallel Ports -@cindex Windows Parallel Ports +@cindex Windows parallel ports @noindent AVRDUDE will accept 3 Windows parallel port names: lpt1, lpt2, or diff --git a/src/dryrun.c b/src/dryrun.c index 9e0c9074..3adfa4a2 100644 --- a/src/dryrun.c +++ b/src/dryrun.c @@ -155,7 +155,7 @@ static int dryrun_page_erase(const PROGRAMMER *pgm, const AVRPART *p, const AVRM if(!(dmem = avr_locate_mem(dry.dp, m->desc))) Return("cannot locate %s %s memory for paged write", dry.dp->desc, m->desc); - if(!avr_has_paged_access(pgm, dmem) || addr >= (unsigned) dmem->size) + if(!avr_has_paged_access(pgm, dry.dp, dmem) || addr >= (unsigned) dmem->size) Return("%s does not support paged access", dmem->desc); addr &= ~(dmem->page_size-1); if(addr + dmem->page_size > (unsigned) dmem->size) @@ -294,24 +294,28 @@ static int flashlayout(const PROGRAMMER *pgm, const AVRPART *p, const AVRMEM *fl } // Write a vector table to flash addr and return number of bytes written -static int putvectortable(const AVRPART *p, const AVRMEM *flm, int addr) { +static int putvectortable(const AVRPART *p, const AVRMEM *flm, int addr, int round32) { int vecsz = flm->size <= 8192? 2: 4, ret = p->n_interrupts * vecsz; int app = (ret + vecsz - 2)/2; // Distance to application in words for(int i = 0; i < ret; i += vecsz) { // First store rjmps to after table flm->buf[addr + i] = app; flm->buf[addr + i + 1] = 0xc0 + (app>>8); // rjmp app, rjmp app, ... + if(vecsz == 4) // Put nop behind rjmp + flm->buf[addr+i+2] = 0, flm->buf[addr+i+3] = 0; app -= vecsz/2; } for(int i=0; i < vecsz; i++) // Leave one vector gap - flm->buf[addr + ret++] = ' '; + flm->buf[addr + ret++] = round32? ' ': 0; - flm->buf[addr + ret++] = 0xff; // Put endless lopp as application - flm->buf[addr + ret++] = 0xcf; + if(round32) { + flm->buf[addr + ret++] = 0xff; // Put endless loop rjmp .-2 as application + flm->buf[addr + ret++] = 0xcf; - // Then round up to multiples of 32 - while(ret%32) - flm->buf[addr + ret++] = ' '; + // Then round up to multiples of 32 + while(ret%32) + flm->buf[addr + ret++] = ' '; + } return ret; } @@ -404,102 +408,32 @@ static void putbanner(const AVRMEM *flm, int addr, int n, int bi) { } } -// Is the opcode of benign nature, ie, not touching SRAM, I/O regs or flash? -static int is_benign_opcode(int op) { - static const struct { int mask, result; } benign[] = { - {0xfc00, 0x0c00}, // 0000 11rd dddd rrrr: add Rd, Rr - {0xfc00, 0x1c00}, // 0001 11rd dddd rrrr: adc Rd, Rr - {0xff00, 0x9600}, // 1001 0110 KKdd KKKK: adiw Rd, K - {0xfc00, 0x1800}, // 0001 10rd dddd rrrr: sub Rd, Rr - {0xf000, 0x5000}, // 0101 KKKK dddd KKKK: subi Rd, K - {0xfc00, 0x0800}, // 0000 10rd dddd rrrr: sbc Rd, Rr - {0xf000, 0x4000}, // 0100 KKKK dddd KKKK: sbci Rd, K - {0xff00, 0x9700}, // 1001 0111 KKdd KKKK: sbiw Rd, K - {0xfc00, 0x2000}, // 0010 00rd dddd rrrr: and Rd, Rr - {0xf000, 0x7000}, // 0111 KKKK dddd KKKK: andi Rd, K - {0xfc00, 0x2800}, // 0010 10rd dddd rrrr: or Rd, Rr - {0xf000, 0x6000}, // 0110 KKKK dddd KKKK: ori Rd, K - {0xfc00, 0x2400}, // 0010 01rd dddd rrrr: eor Rd, Rr - {0xfe0f, 0x9400}, // 1001 010d dddd 0000: com Rd - {0xfe0f, 0x9401}, // 1001 010d dddd 0001: neg Rd - {0xfe0f, 0x9403}, // 1001 010d dddd 0011: inc Rd - {0xfe0f, 0x940a}, // 1001 010d dddd 1010: dec Rd - {0xfc00, 0x9c00}, // 1001 11rd dddd rrrr: mul Rd, Rr - {0xff00, 0x0200}, // 0000 0010 dddd rrrr: muls Rd, Rr - {0xff88, 0x0300}, // 0000 0011 0ddd 0rrr: mulsu Rd, Rr - {0xff88, 0x0308}, // 0000 0011 0ddd 1rrr: fmul Rd, Rr - {0xff88, 0x0380}, // 0000 0011 1ddd 0rrr: fmuls Rd, Rr - {0xff88, 0x0388}, // 0000 0011 1ddd 1rrr: fmulsu Rd, Rr - // {0xff0f, 0x940b}, // 1001 0100 KKKK 1011: des K - {0xfc00, 0x1000}, // 0001 00rd dddd rrrr: cpse Rd, Rr - {0xfc00, 0x1400}, // 0001 01rd dddd rrrr: cp Rd, Rr - {0xfc00, 0x0400}, // 0000 01rd dddd rrrr: cpc Rd, Rr - {0xf000, 0x3000}, // 0011 KKKK dddd KKKK: cpi Rd, K - {0xfe08, 0xfc00}, // 1111 110r rrrr 0bbb: sbrc Rr, b - {0xfe08, 0xfe00}, // 1111 111r rrrr 0bbb: sbrs Rr, b - {0xfc00, 0x2c00}, // 0010 11rd dddd rrrr: mov Rd, Rr - {0xff00, 0x0100}, // 0000 0001 dddd rrrr: movw Rd, Rr - {0xf000, 0xe000}, // 1110 KKKK dddd KKKK: ldi Rd, K - {0xfe0f, 0x9406}, // 1001 010d dddd 0110: lsr Rd - {0xfe0f, 0x9407}, // 1001 010d dddd 0111: ror Rd - {0xfe0f, 0x9405}, // 1001 010d dddd 0101: asr Rd - {0xfe0f, 0x9402}, // 1001 010d dddd 0010: swap Rd - {0xfe08, 0xfa00}, // 1111 101d dddd 0bbb: bst Rr, b - {0xfe08, 0xf800}, // 1111 100d dddd 0bbb: bld Rd, b - {0xffff, 0x9408}, // 1001 0100 0000 1000: sec - {0xffff, 0x9488}, // 1001 0100 1000 1000: clc - {0xffff, 0x9428}, // 1001 0100 0010 1000: sen - {0xffff, 0x94a8}, // 1001 0100 1010 1000: cln - {0xffff, 0x9418}, // 1001 0100 0001 1000: sez - {0xffff, 0x9498}, // 1001 0100 1001 1000: clz - {0xffff, 0x94f8}, // 1001 0100 1111 1000: cli - {0xffff, 0x9448}, // 1001 0100 0100 1000: ses - {0xffff, 0x94c8}, // 1001 0100 1100 1000: cls - {0xffff, 0x9438}, // 1001 0100 0011 1000: sev - {0xffff, 0x94b8}, // 1001 0100 1011 1000: clv - {0xffff, 0x9468}, // 1001 0100 0110 1000: set - {0xffff, 0x94e8}, // 1001 0100 1110 1000: clt - {0xffff, 0x9458}, // 1001 0100 0101 1000: seh - {0xffff, 0x94d8}, // 1001 0100 1101 1000: clh - {0xffff, 0x95a8}, // 1001 0101 1010 1000: wdr - {0xffff, 0x0000}, // 0000 0000 0000 0000: nop - }; - - for(size_t i = 0; i < sizeof benign/sizeof*benign; i++) - if((op & benign[i].mask) == benign[i].result) - return 1; - return 0; +// Put single 16-bit opcode into memory +static void putop16(unsigned char *addr, int op) { + addr[0] = op, addr[1] = op>>8; } -// Put n/2 random benign opcodes into memory at addr -static void putcode(const AVRMEM *flm, int addr, int n) { - int i = 0, op; +// Put n/2 random benign opcodes compatible with part into memory at addr +static void putcode(const AVRPART *p, const AVRMEM *flm, int addr, int n) { + int i, op, inrange, pc, end = addr + n/2*2, avrlevel = avr_get_archlevel(p); - if(n < 2) - return; - if(n < 4) - goto endless; - - for(; i < n/2 - 2; i++) { + for(i = 0; i < n/2; i++) { do { - op = random() & 0xffff; - } while(!is_benign_opcode(op)); - flm->buf[addr + 2*i] = op; // FIXME: relying on little endian here (and below) - flm->buf[addr + 2*i + 1] = op>>8; + inrange = 0; + // Last opcode is a long backward jump; the others are random + op = i == n/2-1? dist2rjmp(-2*(i<2048? i: 2047)): random() & 0xffff; + if(op16_is_benign(op, avrlevel)) + inrange = (pc = op16_target(addr+2*i, op)) >= addr && pc < end; + } while(!inrange); + putop16(flm->buf + addr + 2*i, op); } - - flm->buf[addr+2*i] = 0; - flm->buf[addr+2*i+1] = 0; // nop (in case last opcode was of skip-next-instruction type - i++; - -endless: - flm->buf[addr+2*i] = 255; - flm->buf[addr+2*i+1] = 0xcf; // rjmp .-2 (endless loop) } // Write valid opcodes to flash (banners for -xinit, random code for -xrandom) -static void putflash(const PROGRAMMER *pgm, const AVRMEM *flm, int addr, int n, int bi) { +static void putflash(const PROGRAMMER *pgm, const AVRPART *p, const AVRMEM *flm, int addr, int n, int bi) { + unsigned char *top = flm->buf+addr+n-4; + if(dry.random) { switch(bi) { case U384: case U512: case BDATA: // Bootloader stuff, reduce code length a little @@ -509,12 +443,17 @@ static void putflash(const PROGRAMMER *pgm, const AVRMEM *flm, int addr, int n, n -= random()%(3*n/4); } if(bi != ADATA) { - putcode(flm, addr, n); - return; + putcode(p, flm, addr, n); + goto seal; } bi = RND; // Make apptable data random @/space sequences } putbanner(flm, addr, n, bi); + +seal: // Put 1-2 endless loops in top memory section + if(*top == 0xff) + putop16(top, 0xcfff); + putop16(top+2, 0xcfff); } // Initialise a user writable memory other than flash or fuses @@ -695,7 +634,7 @@ static void dryrun_enable(PROGRAMMER *pgm, const AVRPART *p) { if(flashlayout(pgm, q, flm, up, cp, nc) < 0) return; - int vtb = putvectortable(q, flm, dry.appstart), urbtsz = 0; + int vtb = putvectortable(q, flm, dry.appstart, dry.init), urbtsz = 0; int urboot = random()%3 && dry.bootsize <= 512 && flm->size >= 1024 && flm->size >= 4*dry.bootsize && (q->prog_modes & PM_Classic) && (q->prog_modes & PM_SPM); @@ -709,21 +648,18 @@ static void dryrun_enable(PROGRAMMER *pgm, const AVRPART *p) { dry.bootstart = dry.appsize; } int ubaddr = dry.bootstart; - putflash(pgm, flm, ubaddr, urbtsz, urbtsz==384? U384: U512); - flm->buf[ubaddr] = 0xff; flm->buf[ubaddr+1] = 0xcf; // rjmp .-2 + putflash(pgm, dry.dp, flm, ubaddr, urbtsz, urbtsz==384? U384: U512); } else if(dry.bootsize) { int btb = 0; if(dry.bootsize >= 2048) - btb = putvectortable(q, flm, dry.bootstart); - putflash(pgm, flm, dry.bootstart + btb, dry.bootsize - btb, BDATA); - flm->buf[dry.bootstart] = 0xff; flm->buf[dry.bootstart+1] = 0xcf; // rjmp .-2 + btb = putvectortable(q, flm, dry.bootstart, dry.init); + putflash(pgm, dry.dp, flm, dry.bootstart + btb, dry.bootsize - btb, BDATA); } - if(dry.datasize) { - putflash(pgm, flm, dry.datastart, dry.datasize, ADATA); - } + if(dry.datasize) + putflash(pgm, dry.dp, flm, dry.datastart, dry.datasize, ADATA); - putflash(pgm, flm, dry.appstart+vtb, dry.appsize-vtb-urbtsz, ROCKS); + putflash(pgm, dry.dp, flm, dry.appstart+vtb, dry.appsize-vtb-urbtsz, ROCKS); for(int i = 0; i < flm->size; i += flm->page_size) sharedflash(pgm, flm, i, flm->page_size); @@ -1040,15 +976,15 @@ static int dryrun_parseextparams(const PROGRAMMER *pgm, const LISTID extparms) { for(LNODEID ln = lfirst(extparms); ln; ln = lnext(ln)) { const char *xpara = ldata(ln); - if(str_starts(xpara, "init")) { + if(str_eq(xpara, "init")) { dry.init = 1; continue; } - if(str_starts(xpara, "random")) { + if(str_eq(xpara, "random")) { dry.random = 1; continue; } - if(str_starts(xpara, "seed=")) { + if(str_starts(xpara, "seed=") || str_starts(xpara, "init=") || str_starts(xpara, "random=")) { const char *errptr; int seed = str_int(strchr(xpara, '=')+1, STR_INT32, &errptr); if(errptr) { @@ -1057,6 +993,10 @@ static int dryrun_parseextparams(const PROGRAMMER *pgm, const LISTID extparms) { break; } dry.seed = seed; + if(str_starts(xpara, "init")) + dry.init = 1; + else if(str_starts(xpara, "random")) + dry.random = 1; continue; } if(str_eq(xpara, "help")) { @@ -1069,10 +1009,12 @@ static int dryrun_parseextparams(const PROGRAMMER *pgm, const LISTID extparms) { rc = -1; } msg_error("%s -c %s extended options:\n", progname, pgmid); - msg_error(" -x init Initialise memories with human-readable patterns (1, 2, 3)\n"); - msg_error(" -x random Initialise memories with random code/values (1, 3)\n"); - msg_error(" -x seed= Seed random number generator with , n>0, default time(NULL)\n"); - msg_error(" -x help Show this help menu and exit\n"); + msg_error(" -x init Initialise memories with human-readable patterns (1, 2, 3)\n"); + msg_error(" -x init= Shortcut for -x init -x seed=\n"); + msg_error(" -x random Initialise memories with random code/values (1, 3)\n"); + msg_error(" -x random= Shortcut for -x random -x seed=\n"); + msg_error(" -x seed= Seed random number generator with , n>0, default time(NULL)\n"); + msg_error(" -x help Show this help menu and exit\n"); msg_error("Notes:\n"); msg_error(" (1) -x init and -x random randomly configure flash wrt boot/data/code length\n"); msg_error(" (2) Patterns can best be seen with fixed-width font on -U flash:r:-:I\n"); diff --git a/src/jtag3.c b/src/jtag3.c index e164a157..00741cae 100644 --- a/src/jtag3.c +++ b/src/jtag3.c @@ -19,7 +19,44 @@ */ /* - * avrdude interface for Atmel JTAGICE3 programmer + * Avrdude interface for Atmel JTAGICE3 programmer + * + * + * Scope + * + * Code in this file serves the following programmers + * $ avrdude -c "*"/d | grep "'jtagice3" | cut -f2 -d\' + * + * These are + * - jtag3, jtag3pdi, jtag3updi, jtag3dw, jtag3isp + * - xplainedpro = xplainedpro_jtag, xplainedpro_pdi, xplainedpro_updi + * - xplainedmini = xplainedmini_isp, xplainedmini_dw, xplainedmini_updi, xplainedmini_tpi + * - atmelice = atmelice_jtag, atmelice_pdi, atmelice_updi, atmelice_dw, atmelice_isp, atmelice_tpi + * - powerdebugger = powerdebugger_jtag, powerdebugger_pdi, powerdebugger_updi, powerdebugger_dw, powerdebugger_isp, powerdebugger_tpi + * - pickit4 = pickit4_jtag, pickit4_updi, pickit4_pdi, pickit4_isp, pickit4_tpi + * - snap = snap_jtag, snap_updi, snap_pdi, snap_isp, snap_tpi + * - pkobn_updi + * + * + * Issues + * + * - ATMELICE3 is only recognised correctly in USB High-Speed mode this + * also relates to the hidapi and libusb backends, see + * https://github.com/avrdudes/avrdude/issues/1221 + * + * + * Limitations + * + * - jtag3_page_erase() does not work in the bootrow section of the + * AVR-DU series, ie, can only be written correctly once unless the + * chip-erase command is performed. Confirmed: bootrow page-erase fails + * for Curiosity Nano AVR32DU32 ICE-FW(nEDBG) <= 1.31 (rel 39) + * + * - Trace output -vvvv is not complete and would benefit from enhancing + * + * - High-Voltage Programming on TPI parts not implemented + * + * - Procedures to change the behaviour of the "Target-RESET pin" are unknown or not implemented */ #include @@ -706,6 +743,7 @@ static int jtag3_edbg_recv_frame(const PROGRAMMER *pgm, unsigned char **msg) { // Documentation says: // "FragmentInfo 0x00 indicates that no response data is // available, and the rest of the packet is ignored." + cx->usb_access_error = 1; // Also end up here on wrong USB permissions pmsg_notice("%s(): no response available\n", __func__); mmt_free(*msg); mmt_free(request); @@ -1645,8 +1683,11 @@ int jtag3_open_common(PROGRAMMER *pgm, const char *port, int mode_switch) { } // If the config entry did not specify a USB PID, insert the default one. - if (lfirst(pgm->usbpid) == NULL) - ladd(pgm->usbpid, (void *)USB_DEVICE_JTAGICE3); + if (lfirst(pgm->usbpid) == NULL) { + int *pidp = mmt_malloc(sizeof*pidp); + *pidp = USB_DEVICE_JTAGICE3; + ladd(pgm->usbpid, pidp); + } pinfo.usbinfo.vid = pgm->usbvid? pgm->usbvid: USB_VENDOR_ATMEL; @@ -1705,6 +1746,7 @@ int jtag3_open_common(PROGRAMMER *pgm, const char *port, int mode_switch) { } if(pic_mode >= 0) { msg_error("\n"); + cx->usb_access_error = 0; pmsg_error("%s in %s mode detected\n", pgmstr, pinfo.usbinfo.pid == bl_pid? "bootloader": "PIC"); if(mode_switch == PK4_SNAP_MODE_AVR) { @@ -1719,7 +1761,7 @@ int jtag3_open_common(PROGRAMMER *pgm, const char *port, int mode_switch) { imsg_error("run %s again to continue the session\n\n", progname); } else { pmsg_error("to switch into AVR mode try\n"); - imsg_error("$ %s -c%s -p%s -P%s -x mode=avr\n", progname, pgmid, partdesc, port); + imsg_error("$ %s -c %s -p %s -P %s -x mode=avr\n", progname, pgmid, partdesc, port); } serial_close(&pgm->fd); return LIBAVRDUDE_EXIT;; @@ -1883,6 +1925,10 @@ static int jtag3_page_erase(const PROGRAMMER *pgm, const AVRPART *p, const AVRME cmd[3] = XMEGA_ERASE_EEPROM_PAGE; } else if (mem_is_userrow(m)) { cmd[3] = XMEGA_ERASE_USERSIG; + } else if (mem_is_bootrow(m)) { + // Currently, AVR-DU BOOTROW cannot be erased with CMD3_ERASE_MEMORY + // Note ATDF: + cmd[3] = XMEGA_ERASE_USERSIG; // Tentative for AVR-DU and AVR-EB series } else { cmd[3] = XMEGA_ERASE_APP_PAGE; } @@ -1952,7 +1998,7 @@ static int jtag3_paged_write(const PROGRAMMER *pgm, const AVRPART *p, const AVRM } cmd[3] = p->prog_modes & (PM_PDI | PM_UPDI)? MTYPE_EEPROM_XMEGA: MTYPE_EEPROM_PAGE; PDATA(pgm)->eeprom_pageaddr = (unsigned long)-1L; - } else if (mem_is_userrow(m)) { + } else if (mem_is_userrow(m) || mem_is_bootrow(m)) { cmd[3] = MTYPE_USERSIG; } else if (mem_is_boot(m)) { cmd[3] = MTYPE_BOOT_FLASH; @@ -2040,7 +2086,7 @@ static int jtag3_paged_load(const PROGRAMMER *pgm, const AVRPART *p, const AVRME return -1; } else if (mem_is_sigrow(m)) { cmd[3] = MTYPE_PRODSIG; - } else if (mem_is_userrow(m)) { + } else if (mem_is_userrow(m) || mem_is_bootrow(m)) { cmd[3] = MTYPE_USERSIG; } else if (mem_is_boot(m)) { cmd[3] = MTYPE_BOOT_FLASH; @@ -2149,7 +2195,7 @@ static int jtag3_read_byte(const PROGRAMMER *pgm, const AVRPART *p, const AVRMEM cmd[3] = MTYPE_LOCK_BITS; if (pgm->flag & PGM_FL_IS_DW) unsupp = 1; - } else if (mem_is_userrow(mem)) { + } else if (mem_is_userrow(mem) || mem_is_bootrow(mem)) { cmd[3] = MTYPE_USERSIG; } else if (mem_is_sigrow(mem)) { if (p->prog_modes & (PM_PDI | PM_UPDI)) { @@ -2208,10 +2254,14 @@ static int jtag3_read_byte(const PROGRAMMER *pgm, const AVRPART *p, const AVRMEM return -1; } } else if(mem_is_in_sigrow(mem)) { // sigrow sub-memories but not signature nor sigrow itself - cmd[3] = (p->prog_modes & PM_UPDI)? MTYPE_SIGN_JTAG: MTYPE_PRODSIG; - AVRMEM *sigrow = avr_locate_sigrow(p); - if(sigrow) - addr += mem->offset - sigrow->offset; // Adjust offset for parent memory + if (p->prog_modes & (PM_PDI | PM_UPDI)) { + cmd[3] = MTYPE_PRODSIG; + } else { + cmd[3] = addr&1? MTYPE_OSCCAL_BYTE: MTYPE_SIGN_JTAG; + addr /= 2; + if (pgm->flag & PGM_FL_IS_DW) + unsupp = 1; + } } else { pmsg_error("unknown memory %s\n", mem->desc); return -1; @@ -2322,7 +2372,7 @@ static int jtag3_write_byte(const PROGRAMMER *pgm, const AVRPART *p, const AVRME cmd[3] = MTYPE_LOCK_BITS; if (pgm->flag & PGM_FL_IS_DW) unsupp = 1; - } else if (mem_is_userrow(mem)) { + } else if (mem_is_userrow(mem) || mem_is_bootrow(mem)) { cmd[3] = MTYPE_USERSIG; } else if (mem_is_io(mem) || mem_is_sram(mem)) cmd[3] = MTYPE_SRAM; @@ -2785,22 +2835,31 @@ static unsigned char jtag3_mtype(const PROGRAMMER *pgm, const AVRPART *p, unsign } static unsigned int jtag3_memaddr(const PROGRAMMER *pgm, const AVRPART *p, const AVRMEM *m, unsigned long addr) { - if (p->prog_modes & PM_PDI) { + if(is_pdi(p)) { // Xmega /* * All memories but "flash" are smaller than boot_start anyway, so * no need for an extra check we are operating on "flash" */ if(addr >= PDATA(pgm)->boot_start) addr -= PDATA(pgm)->boot_start; - } else if(p->prog_modes & PM_UPDI) { // Modern AVR8X part + if(mem_is_in_sigrow(m)) { + AVRMEM *sigrow = avr_locate_sigrow(p); + if(sigrow) + addr += m->offset - sigrow->offset; + } + } else if(is_updi(p)) { // Modern AVR8X part if(!mem_is_flash(m)) if(m->size >= 1) addr += m->offset; } else { // Classic part if(mem_is_userrow(m)) addr += m->offset; + else if(mem_is_in_sigrow(m)) { + AVRMEM *sigrow = avr_locate_sigrow(p); + if(sigrow) + addr += m->offset - sigrow->offset; + } } - return addr; } diff --git a/src/jtagmkII.c b/src/jtagmkII.c index 46c1dc99..7b0609b2 100644 --- a/src/jtagmkII.c +++ b/src/jtagmkII.c @@ -25,7 +25,17 @@ * avrdude interface for Atmel JTAG ICE mkII programmer * * The AVR Dragon also uses the same protocol, so it is handled here - * as well. + * + * + * Scope + * + * Code in this file serves the following programmers + * $ avrdude -c "*"/d | grep -P "'(jtagmkii|dragon)" | cut -f2 -d\' + * + * - jtagmkII = jtag2slow, jtag2fast = jtag2, jtag2isp, jtag2dw, jtag2pdi, jtag2updi = nanoevery + * - jtagmkII_avr32 = jtag2avr32 + * - dragon_jtag, dragon_isp, dragon_pp, dragon_hvsp, dragon_dw, dragon_pdi + * */ #include @@ -1812,7 +1822,7 @@ static int jtagmkII_page_erase(const PROGRAMMER *pgm, const AVRPART *p, const AV cmd[1] = XMEGA_ERASE_BOOT_PAGE; } else if (mem_is_eeprom(m)) { cmd[1] = XMEGA_ERASE_EEPROM_PAGE; - } else if (mem_is_userrow(m)) { + } else if (mem_is_userrow(m) || mem_is_bootrow(m)) { cmd[1] = XMEGA_ERASE_USERSIG; } else if (mem_is_boot(m)) { cmd[1] = XMEGA_ERASE_BOOT_PAGE; @@ -1909,7 +1919,7 @@ static int jtagmkII_paged_write(const PROGRAMMER *pgm, const AVRPART *p, const A } cmd[1] = p->prog_modes & (PM_PDI | PM_UPDI)? MTYPE_EEPROM_XMEGA: MTYPE_EEPROM_PAGE; PDATA(pgm)->eeprom_pageaddr = (unsigned long)-1L; - } else if (mem_is_userrow(m)) { + } else if (mem_is_userrow(m) || mem_is_bootrow(m)) { cmd[1] = MTYPE_USERSIG; } else if (mem_is_boot(m)) { cmd[1] = MTYPE_BOOT_FLASH; @@ -2012,7 +2022,7 @@ static int jtagmkII_paged_load(const PROGRAMMER *pgm, const AVRPART *p, const AV return -1; } else if (mem_is_sigrow(m)) { cmd[1] = MTYPE_PRODSIG; - } else if (mem_is_userrow(m)) { + } else if (mem_is_userrow(m) || mem_is_bootrow(m)) { cmd[1] = MTYPE_USERSIG; } else if (mem_is_boot(m)) { cmd[1] = MTYPE_BOOT_FLASH; @@ -2139,7 +2149,7 @@ static int jtagmkII_read_byte(const PROGRAMMER *pgm, const AVRPART *p, const AVR cmd[1] = MTYPE_LOCK_BITS; if (pgm->flag & PGM_FL_IS_DW) unsupp = 1; - } else if (mem_is_userrow(mem)) { + } else if (mem_is_userrow(mem) || mem_is_bootrow(mem)) { cmd[1] = MTYPE_USERSIG; } else if (mem_is_sigrow(mem)) { if (p->prog_modes & (PM_PDI | PM_UPDI)) { @@ -2148,8 +2158,10 @@ static int jtagmkII_read_byte(const PROGRAMMER *pgm, const AVRPART *p, const AVR } else { cmd[1] = addr&1? MTYPE_OSCCAL_BYTE: MTYPE_SIGN_JTAG; addr /= 2; + if (pgm->flag & PGM_FL_IS_DW) + unsupp = 1; } - } else if (mem_is_calibration(mem)) { + } else if(is_classic(p) && mem_is_calibration(mem)) { cmd[1] = MTYPE_OSCCAL_BYTE; if (pgm->flag & PGM_FL_IS_DW) unsupp = 1; @@ -2182,12 +2194,16 @@ static int jtagmkII_read_byte(const PROGRAMMER *pgm, const AVRPART *p, const AVR } return 0; } - } else if ((p->prog_modes & (PM_PDI | PM_UPDI)) && mem_is_in_sigrow(mem)) { - cmd[1] = MTYPE_PRODSIG; + } else if (mem_is_in_sigrow(mem)) { pmsg_notice2("in_sigrow addr 0x%05lx\n", addr); - } else if (mem_is_in_sigrow(mem)) { // Classic part - cmd[1] = addr&1? MTYPE_OSCCAL_BYTE: MTYPE_SIGN_JTAG; - addr /= 2; + if (p->prog_modes & (PM_PDI | PM_UPDI)) { + cmd[1] = MTYPE_PRODSIG; + } else { + cmd[1] = addr&1? MTYPE_OSCCAL_BYTE: MTYPE_SIGN_JTAG; + addr /= 2; + if (pgm->flag & PGM_FL_IS_DW) + unsupp = 1; + } } else if (mem_is_io(mem) || mem_is_sram(mem)) { cmd[1] = MTYPE_FLASH; addr += avr_data_offset(p); @@ -2307,7 +2323,7 @@ static int jtagmkII_write_byte(const PROGRAMMER *pgm, const AVRPART *p, const AV addr = mem_fuse_offset(mem); if (pgm->flag & PGM_FL_IS_DW) unsupp = 1; - } else if (mem_is_userrow(mem)) { + } else if (mem_is_userrow(mem) || mem_is_bootrow(mem)) { cmd[1] = MTYPE_USERSIG; } else if (mem_is_lock(mem)) { cmd[1] = MTYPE_LOCK_BITS; diff --git a/src/lexer.l b/src/lexer.l index 230813ab..d33ad4ba 100644 --- a/src/lexer.l +++ b/src/lexer.l @@ -191,31 +191,22 @@ default_programmer { yylval=NULL; return K_DEFAULT_PROGRAMMER; } default_serial { yylval=NULL; return K_DEFAULT_SERIAL; } default_spi { yylval=NULL; return K_DEFAULT_SPI; } default_linuxgpio { yylval=NULL; return K_DEFAULT_LINUXGPIO; } -devicecode { yylval=NULL; ccap(); return K_DEVICECODE; } eeprom { yylval=NULL; return K_EEPROM; } eeprom_instr { yylval=NULL; ccap(); return K_EEPROM_INSTR; } enablepageprogramming { yylval=NULL; ccap(); return K_ENABLEPAGEPROGRAMMING; } errled { yylval=NULL; ccap(); return K_ERRLED; } flash { yylval=NULL; return K_FLASH; } flash_instr { yylval=NULL; ccap(); return K_FLASH_INSTR; } -has_debugwire { yylval=NULL; ccap(); return K_HAS_DW; } -has_jtag { yylval=NULL; ccap(); return K_HAS_JTAG; } -has_pdi { yylval=NULL; ccap(); return K_HAS_PDI; } -has_tpi { yylval=NULL; ccap(); return K_HAS_TPI; } -has_updi { yylval=NULL; ccap(); return K_HAS_UPDI; } hvsp_controlstack { yylval=NULL; ccap(); return K_HVSP_CONTROLSTACK; } hvupdi_support { yylval=NULL; ccap(); return K_HVUPDI_SUPPORT; } id { yylval=NULL; ccap(); return K_ID; } io { yylval=new_token(K_IO); return K_IO; } is_at90s1200 { yylval=NULL; ccap(); return K_IS_AT90S1200; } -is_avr32 { yylval=NULL; ccap(); return K_IS_AVR32; } linuxgpio { yylval=NULL; ccap(); return K_LINUXGPIO; } load_ext_addr { yylval=new_token(K_LOAD_EXT_ADDR); ccap(); return K_LOAD_EXT_ADDR; } loadpage_hi { yylval=new_token(K_LOADPAGE_HI); ccap(); return K_LOADPAGE_HI; } loadpage_lo { yylval=new_token(K_LOADPAGE_LO); ccap(); return K_LOADPAGE_LO; } memory { yylval=NULL; ccap(); current_strct = COMP_AVRMEM; return K_MEMORY; } -miso { yylval=NULL; ccap(); yywarning("miso is deprecated, will be removed in v8.0, use sdi"); return K_SDI; } -mosi { yylval=NULL; ccap(); yywarning("mosi is deprecated, will be removed in v8.0, use sdo"); return K_SDO; } NULL { yylval=NULL; return K_NULL; } page_size { yylval=NULL; ccap(); return K_PAGE_SIZE; } parallel { yylval=NULL; ccap(); return K_PARALLEL; } @@ -223,6 +214,8 @@ parent { yylval=NULL; return K_PARENT; } part { yylval=NULL; ccap(); current_strct = COMP_AVRPART; return K_PART; } pgm_enable { yylval=new_token(K_PGM_ENABLE); ccap(); return K_PGM_ENABLE; } pgmled { yylval=NULL; ccap(); return K_PGMLED; } +pico { yylval=NULL; ccap(); return K_SDO; } +poci { yylval=NULL; ccap(); return K_SDI; } pp_controlstack { yylval=NULL; ccap(); return K_PP_CONTROLSTACK; } (programmer|serialadapter) { yylval=NULL; ccap(); current_strct = COMP_PROGRAMMER; cx->lex_kw_is_programmer = *yytext == 'p'; return K_PROGRAMMER; } diff --git a/src/libavrdude.h b/src/libavrdude.h index 66b7a0f7..a3c04c05 100644 --- a/src/libavrdude.h +++ b/src/libavrdude.h @@ -262,6 +262,42 @@ typedef struct opcode { #define PM_Classic (PM_TPI | PM_ISP | PM_HVSP | PM_HVPP | PM_debugWIRE | PM_JTAG | PM_JTAGmkI) #define PM_ALL 0x1fff // All programming interfaces +// Shortcut test for programmers and parts +#define is_spm(x) (!!((x)->prog_modes & PM_SPM)) +#define is_tpi(x) (!!((x)->prog_modes & PM_TPI)) +#define is_isp(x) (!!((x)->prog_modes & PM_ISP)) +#define is_pdi(x) (!!((x)->prog_modes & PM_PDI)) +#define is_updi(x) (!!((x)->prog_modes & PM_UPDI)) +#define is_hvsp(x) (!!((x)->prog_modes & PM_HVSP)) +#define is_hvpp(x) (!!((x)->prog_modes & PM_HVPP)) +#define is_debugwire(x) (!!((x)->prog_modes & PM_debugWIRE)) +#define is_jtag(x) (!!((x)->prog_modes & PM_JTAG)) +#define is_jtagmki(x) (!!((x)->prog_modes & PM_JTAGmkI)) +#define is_xmegajtag(x) (!!((x)->prog_modes & PM_XMEGAJTAG)) +#define is_avr32jtag(x) (!!((x)->prog_modes & PM_AVR32JTAG)) +#define is_awire(x) (!!((x)->prog_modes & PM_aWire)) +#define is_classic(x) (!!((x)->prog_modes & PM_Classic)) + +// Set of overlapping programming modes of programmer and part +#define joint_pm(pgm, p) ((pgm)->prog_modes & (p)->prog_modes) + +// Shortcut test whether both programmer and part have that programming mode +#define both_spm(pgm, p) (!!(joint_pm(pgm, p) & PM_SPM)) +#define both_tpi(pgm, p) (!!(joint_pm(pgm, p) & PM_TPI)) +#define both_isp(pgm, p) (!!(joint_pm(pgm, p) & PM_ISP)) +#define both_pdi(pgm, p) (!!(joint_pm(pgm, p) & PM_PDI)) +#define both_updi(pgm, p) (!!(joint_pm(pgm, p) & PM_UPDI)) +#define both_hvsp(pgm, p) (!!(joint_pm(pgm, p) & PM_HVSP)) +#define both_hvpp(pgm, p) (!!(joint_pm(pgm, p) & PM_HVPP)) +#define both_debugwire(pgm, p) (!!(joint_pm(pgm, p) & PM_debugWIRE)) +#define both_jtag(pgm, p) (!!(joint_pm(pgm, p) & PM_JTAG)) +#define both_jtagmki(pgm, p) (!!(joint_pm(pgm, p) & PM_JTAGmkI)) +#define both_xmegajtag(pgm, p) (!!(joint_pm(pgm, p) & PM_XMEGAJTAG)) +#define both_avr32jtag(pgm, p) (!!(joint_pm(pgm, p) & PM_AVR32JTAG)) +#define both_awire(pgm, p) (!!(joint_pm(pgm, p) & PM_aWire)) +#define both_classic(pgm, p) (!!(joint_pm(pgm, p) & PM_Classic)) + + #define HV_UPDI_VARIANT_0 0 /* Shared UPDI/GPIO/RESET pin, HV on UPDI pin (tinyAVR0/1/2)*/ #define HV_UPDI_VARIANT_1 1 /* Dedicated UPDI pin, no HV (megaAVR0/AVR-Dx) */ #define HV_UPDI_VARIANT_2 2 /* Shared UPDI pin, HV on _RESET (AVR-DD/AVR-Ex) */ @@ -564,6 +600,8 @@ typedef struct avrmem_alias { AVRMEM *aliased_mem; } AVRMEM_ALIAS; +typedef struct programmer PROGRAMMER; // Forward declaration + #ifdef __cplusplus extern "C" { #endif @@ -601,7 +639,7 @@ AVRMEM * avr_locate_mem_by_type(const AVRPART *p, Memtype type); unsigned int avr_data_offset(const AVRPART *p); AVRMEM_ALIAS * avr_locate_memalias(const AVRPART *p, const char *desc); AVRMEM_ALIAS * avr_find_memalias(const AVRPART *p, const AVRMEM *m_orig); -void avr_mem_display(FILE *f, const AVRPART *p, const char *prefix); +void avr_mem_display(FILE *f, const PROGRAMMER *pgm, const AVRPART *p, const char *prefix); /* Functions for AVRPART structures */ AVRPART * avr_new_part(void); @@ -614,7 +652,7 @@ AVRPART * locate_part_by_signature_pm(const LISTID parts, unsigned char *sig, in int avr_sig_compatible(const unsigned char *sig1, const unsigned char *sig2); char *avr_prog_modes(int pm), *str_prog_modes(int pm), *dev_prog_modes(int pm); -void avr_display(FILE *f, const AVRPART *p, const char *prefix, int verbose); +void avr_display(FILE *f, const PROGRAMMER *pgm, const AVRPART *p, const char *prefix, int verbose); int avr_variants_display(FILE *f, const AVRPART *p, const char *prefix); typedef void (*walk_avrparts_cb)(const char *name, const char *desc, @@ -739,8 +777,6 @@ void pin_set_value(struct pindef * const pindef, const int pin, const bool inver */ void pin_clear_all(struct pindef * const pindef); -typedef struct programmer PROGRAMMER; // Forward declaration - /** * Convert for given programmer new pin definitions to old pin definitions. * @@ -1173,6 +1209,8 @@ int avr_get_cycle_count(const PROGRAMMER *pgm, const AVRPART *p, int *cycles); int avr_put_cycle_count(const PROGRAMMER *pgm, const AVRPART *p, int cycles); +int avr_mem_exclude(const PROGRAMMER *pgm, const AVRPART *p, const AVRMEM *mem); + int avr_get_mem_type(const char *str); int avr_mem_is_flash_type(const AVRMEM *mem); @@ -1197,7 +1235,7 @@ void report_progress(int completed, int total, const char *hdr); void trace_buffer(const char *funstr, const unsigned char *buf, size_t buflen); -int avr_has_paged_access(const PROGRAMMER *pgm, const AVRMEM *m); +int avr_has_paged_access(const PROGRAMMER *pgm, const AVRPART *p, const AVRMEM *m); int avr_read_page_default(const PROGRAMMER *pgm, const AVRPART *p, const AVRMEM *mem, int addr, unsigned char *buf); @@ -1349,7 +1387,7 @@ int update_is_readable(const char *fn); int update_dryrun(const AVRPART *p, UPDATE *upd); -AVRMEM **memory_list(const char *mstr, const AVRPART *p, int *np, int *rwvsoftp, int *dry); +AVRMEM **memory_list(const char *mstr, const PROGRAMMER *pgm, const AVRPART *p, int *np, int *rwvsoftp, int *dry); int memlist_contains_flash(const char *mstr, const AVRPART *p); #ifdef __cplusplus @@ -1701,6 +1739,7 @@ char *str_lc(char *s); char *str_uc(char *s); char *str_lcfirst(char *s); char *str_ucfirst(char *s); +char *str_asciiname(char *s); char *str_utoa(unsigned n, char *buf, int base); char *str_endnumber(const char *str); const char *str_plural(int x); @@ -1725,6 +1764,7 @@ int str_levenshtein(const char *str1, const char *str2, int swap, int subst, int size_t str_weighted_damerau_levenshtein(const char *str1, const char *str2); int str_mcunames_signature(const unsigned char *sigs, int pm, char *p, size_t n); const char *str_ccmcunames_signature(const unsigned char *sigs, int pm); +const char *str_ccpgmids(LISTID pgm_id); int led_set(const PROGRAMMER *pgm, int led); int led_clr(const PROGRAMMER *pgm, int led); @@ -1749,10 +1789,14 @@ int op_width(int op16); int ldi_Rd(int op16); int ldi_K(int op16); AVR_mnemo opcode_mnemo(int op16, int avrlevel); +int op16_is_valid(int op16, int avrlevel); +int op16_is_benign(int op16, int avrlevel); int avr_get_archlevel(const AVRPART *p); AVR_cycle_index avr_get_cycle_index(const AVRPART *p); const char *mnemo_str(int op16); int z_width(int op16, AVR_mnemo *mnenop); +int op16_target(int here, int op16); +int dist2rjmp(int dist); int disasm(const char *buf, int len, int addr, int leadin, int leadout); int disasm_init(const AVRPART *p); @@ -1866,6 +1910,9 @@ typedef struct { // Variable connecting lexer.l and config_gram.y int lex_kw_is_programmer; // Was the K_PROGRAMMER keyword "programmer"? + + // Global variable indicating usb access problems + int usb_access_error; } libavrdude_context; extern libavrdude_context *cx; diff --git a/src/main.c b/src/main.c index 09d3646b..a43a3aa3 100644 --- a/src/main.c +++ b/src/main.c @@ -44,6 +44,9 @@ #include #include #include +#if !defined(WIN32) +#include +#endif #include "avrdude.h" #include "libavrdude.h" @@ -130,16 +133,17 @@ int avrdude_message2(FILE *fp, int lno, const char *file, const char *func, int fprintf(fp, " %s", mt); bols[bi].bol = 0; } - if(verbose >= MSG_NOTICE2 && (msgmode & MSG2_FUNCTION)) - fprintf(fp, " %s()", func); - if(verbose >= MSG_DEBUG && (msgmode & MSG2_FILELINE)) { - const char *pr = strrchr(file, '/'); // Only print basename + if(verbose >= MSG_NOTICE2) { + const char *bfname = strrchr(file, '/'); // Only print basename #if defined (WIN32) - if(!pr) - pr = strrchr(file, '\\'); + if(!bfname) + bfname = strrchr(file, '\\'); #endif - pr = pr? pr+1: file; - fprintf(fp, " [%s:%d]", pr, lno); + bfname = bfname? bfname+1: file; + if(msgmode & MSG2_FUNCTION) + fprintf(fp, " %s()", func); + if(msgmode & MSG2_FILELINE) + fprintf(fp, " %s %d", bfname, lno); } fprintf(fp, ": "); } else if(msgmode & MSG2_INDENT1) { @@ -770,7 +774,7 @@ int main(int argc, char * argv []) /* * process command line arguments */ - while ((ch = getopt(argc, argv, "?Ab:B:c:C:DeE:Fi:l:nNp:OP:qrstT:U:uvVx:yY")) != -1) { + while ((ch = getopt(argc, argv, "?Ab:B:c:C:DeE:Fi:l:nNp:OP:qrtT:U:vVx:")) != -1) { switch (ch) { case 'b': /* override default programmer baud rate */ @@ -887,11 +891,6 @@ int main(int argc, char * argv []) ladd(updates, cmd_update("interactive terminal")); break; - case 's': - case 'u': - pmsg_error("\"safemode\" feature no longer supported\n"); - break; - case 'T': ladd(updates, cmd_update(optarg)); break; @@ -917,11 +916,6 @@ int main(int argc, char * argv []) ladd(extended_params, optarg); break; - case 'y': - case 'Y': - pmsg_error("erase cycle counter no longer supported\n"); - break; - case '?': /* help */ usage(); exit(0); @@ -1123,7 +1117,7 @@ int main(int argc, char * argv []) pgmid = cache_string(default_programmer); // Developer options to print parts and/or programmer entries of avrdude.conf - int dev_opt_c = dev_opt(pgmid); // -c /[dASsrtiBUPTIJWHQ] + int dev_opt_c = dev_opt(pgmid); // -c /[duASsrtiBUPTIJWHQ] int dev_opt_p = dev_opt(partdesc); // -p /[cdoASsrw*tiBUPTIJWHQ] if(dev_opt_c || dev_opt_p) { // See -c/h and or -p/h @@ -1515,7 +1509,7 @@ skipopen: } if (verbose > 0 && quell_progress < 2) { - avr_display(stderr, p, progbuf, verbose); + avr_display(stderr, pgm, p, progbuf, verbose); msg_notice2("\n"); programmer_display(pgm, progbuf); } @@ -1677,8 +1671,8 @@ skipopen: msg_info("\n"); pmsg_error("invalid device signature\n"); if (!ovsigck) { - pmsg_error("expected signature for %s is%s; double\n", p->desc, str_cchex(p->signature, 3, 1)); - imsg_error("check connections and try again, or use -F to carry on regardless\n"); + pmsg_error("expected signature for %s is%s\n", p->desc, str_cchex(p->signature, 3, 1)); + imsg_error(" - double check connections and try again, or use -F to carry on regardless\n"); exitrc = 1; goto main_exit; } @@ -1690,8 +1684,8 @@ skipopen: if (ovsigck) { pmsg_warning("expected signature for %s is%s\n", p->desc, str_cchex(p->signature, 3, 1)); } else { - pmsg_error("expected signature for %s is%s; double\n", p->desc, str_cchex(p->signature, 3, 1)); - imsg_error("check chip or use -F to carry on regardless\n"); + pmsg_error("expected signature for %s is%s\n", p->desc, str_cchex(p->signature, 3, 1)); + imsg_error(" - double check chip or use -F to carry on regardless\n"); exitrc = 1; goto main_exit; } @@ -1806,6 +1800,22 @@ main_exit: pgm->close(pgm); } + if(cx->usb_access_error) { + pmsg_info( + "\nUSB access errors detected; this could have many reasons; if it is\n" + "USB permission problems, avrdude is likely to work when run as root\n" + "but this is not good practice; instead you might want to\n"); +#if 0 && !defined(WIN32) + DIR *dir; + if((dir = opendir("/etc/udev/rules.d"))) { // Linux udev land + closedir(dir); + imsg_info("run the command below to show udev rules recitifying USB access\n" + "$ %s -c %s/u\n", progname, pgmid); + } else +#endif + imsg_info("check out USB port permissions on your OS and set them correctly\n"); + } + msg_info("\n"); pmsg_info("%s done. Thank you.\n", progname); diff --git a/src/micronucleus.c b/src/micronucleus.c index 2b5fe6cf..8bbc596a 100644 --- a/src/micronucleus.c +++ b/src/micronucleus.c @@ -121,6 +121,8 @@ static int micronucleus_check_connection(struct pdata *pdata) { 0, 0, (char*)buffer, sizeof(buffer), MICRONUCLEUS_DEFAULT_TIMEOUT); + if(result < 0) + cx->usb_access_error = 1; return result == sizeof(buffer) ? 0 : -1; } else @@ -133,6 +135,8 @@ static int micronucleus_check_connection(struct pdata *pdata) { 0, 0, (char*)buffer, sizeof(buffer), MICRONUCLEUS_DEFAULT_TIMEOUT); + if(result < 0) + cx->usb_access_error = 1; return result == sizeof(buffer) ? 0 : -1; } } diff --git a/src/pickit2.c b/src/pickit2.c index 3ed519e2..aa676db6 100644 --- a/src/pickit2.c +++ b/src/pickit2.c @@ -1109,15 +1109,15 @@ static int usb_open_device(PROGRAMMER *pgm, struct usb_dev_handle **device, int if ((errorCode = usb_set_configuration(handle, 1)) < 0) { - pmsg_ext_error("cannot set configuration, error code %d, %s\n" - "you may need to run avrdude as root or set up correct usb port permissions", + cx->usb_access_error = 1; + pmsg_ext_error("cannot set configuration, error code %d, %s\n", errorCode, usb_strerror()); } if ((errorCode = usb_claim_interface(handle, 0)) < 0) { - pmsg_ext_error("cannot claim interface, error code %d, %s\n" - "You may need to run avrdude as root or set up correct usb port permissions.", + cx->usb_access_error = 1; + pmsg_ext_error("cannot claim interface, error code %d, %s\n", errorCode, usb_strerror()); } diff --git a/src/stk500v2.c b/src/stk500v2.c index a24db1c3..b07829c2 100644 --- a/src/stk500v2.c +++ b/src/stk500v2.c @@ -2820,7 +2820,7 @@ static int stk500v2_paged_write(const PROGRAMMER *pgm, const AVRPART *p, const A // the read command is common to both methods if (rop == NULL) { - pmsg_error("read instruction not defined for part %s\n", p->desc); + pmsg_error("read instruction not defined for memory %s of part %s\n", m->desc, p->desc); return -1; } memset(cmds, 0, sizeof cmds); @@ -3025,7 +3025,7 @@ static int stk500v2_paged_load(const PROGRAMMER *pgm, const AVRPART *p, const AV // the read command is common to both methods if (rop == NULL) { - pmsg_error("read instruction not defined for part %s\n", p->desc); + pmsg_error("read instruction not defined for memory %s of part %s\n", m->desc, p->desc); return -1; } memset(cmds, 0, sizeof cmds); diff --git a/src/strutil.c b/src/strutil.c index bd22e368..8fc98714 100644 --- a/src/strutil.c +++ b/src/strutil.c @@ -412,6 +412,35 @@ char *str_ucfirst(char *s) { return s; } +// Convert to ASCII name leaving only letters, numbers, underscore, period and dash +char *str_asciiname(char *s) { + for(char *t = s; *t; t++) + switch(*t) { + case '?': *t = 'Q'; break; + case '*': *t = 'X'; break; + case '|': *t = 'I'; break; + case '{': *t = 'l'; break; + case '}': *t = 'j'; break; + case '[': *t = 'L'; break; + case ']': *t = 'J'; break; + case '(': *t = 'L'; break; + case ')': *t = 'J'; break; + case '<': *t = 'l'; break; + case '>': *t = 'j'; break; + case '&': *t = '+'; break; + case '!': *t = 'I'; break; + case '"': *t = 'q'; break; + case '\'': *t = 'q'; break; + case '`': *t = 'q'; break; + case '.': case '-': break; + default: + if(!isascii(*t & 0xff) || !isalnum(*t & 0xff)) + *t = '_'; + } + + return s; +} + // Convert unsigned to ASCII string; caller needs to allocate enough space for buf char *str_utoa(unsigned n, char *buf, int base) { @@ -1422,3 +1451,18 @@ const char *str_ccmcunames_signature(const unsigned char *sigs, int pm) { return str_ccprintf("%s", names); } + +// Returns a comma-separated list of pgm->id names +const char *str_ccpgmids(LISTID pgm_id) { + char ids[1024], *idp = ids; + + for(LNODEID idn=lfirst(pgm_id); idn; idn=lnext(idn)) { + char *id = ldata(idn); + if((idp - ids) + 3 + strlen(id) <= sizeof ids) { + if(idp > ids) + strcpy(idp, ", "), idp += 2; + strcpy(idp, id), idp += strlen(id); + } + } + return str_ccprintf("%s", ids); +} diff --git a/src/term.c b/src/term.c index 473bd87b..85cb2d4c 100644 --- a/src/term.c +++ b/src/term.c @@ -836,7 +836,7 @@ static int cmd_write(const PROGRAMMER *pgm, const AVRPART *p, int argc, const ch msg_notice2("; remaining space filled with %s", argv[argc - 2]); msg_notice2("\n"); - report_progress(0, 1, avr_has_paged_access(pgm, mem)? "Caching": "Writing"); + report_progress(0, 1, avr_has_paged_access(pgm, p, mem)? "Caching": "Writing"); for (i = 0; i < len + bytes_grown; i++) { report_progress(i, len + bytes_grown, NULL); if(!tags[i]) @@ -1270,7 +1270,7 @@ static int cmd_pgerase(const PROGRAMMER *pgm, const AVRPART *p, int argc, const pmsg_error("(pgerase) memory %s not defined for part %s\n", memstr, p->desc); return -1; } - if(!avr_has_paged_access(pgm, mem)) { + if(!avr_has_paged_access(pgm, p, mem)) { pmsg_error("(pgerase) %s memory cannot be paged addressed by %s\n", memstr, pgmid); return -1; } @@ -1974,12 +1974,12 @@ static int cmd_factory(const PROGRAMMER *pgm, const AVRPART *p, int argc, const } for(LNODEID ln=lfirst(p->mem); ln; ln=lnext(ln)) { - m = ldata(ln); - if(mem_is_eeprom(m) || mem_is_user_type(m)) { - args[1] = m->desc; - if(cmd_erase(pgm, p, 2, args) < 0) - ret = -1; - } + if(!avr_mem_exclude(pgm, p, (m = ldata(ln)))) + if(mem_is_eeprom(m) || mem_is_user_type(m)) { + args[1] = m->desc; + if(cmd_erase(pgm, p, 2, args) < 0) + ret = -1; + } } if(pgm->flush_cache(pgm, p) < 0) @@ -1990,9 +1990,10 @@ static int cmd_factory(const PROGRAMMER *pgm, const AVRPART *p, int argc, const // Reset fuses to factory values for(LNODEID ln=lfirst(p->mem); ln; ln=lnext(ln)) - if(mem_is_a_fuse(m = ldata(ln))) - if(fusel_factory(pgm, p, m) < 0) - ret = -1; + if(!avr_mem_exclude(pgm, p, (m = ldata(ln)))) + if(mem_is_a_fuse(m)) + if(fusel_factory(pgm, p, m) < 0) + ret = -1; int fuseok = ret == 0; @@ -2001,12 +2002,12 @@ static int cmd_factory(const PROGRAMMER *pgm, const AVRPART *p, int argc, const ret = -1; for(LNODEID ln=lfirst(p->mem); ln; ln=lnext(ln)) { - m = ldata(ln); - if(mem_is_flash(m) || mem_is_eeprom(m) || mem_is_user_type(m)) { - args[1] = m->desc; - if(cmd_erase(pgm, p, 2, args) < 0) - ret = -1; - } + if(!avr_mem_exclude(pgm, p, (m = ldata(ln)))) + if(mem_is_flash(m) || mem_is_eeprom(m) || mem_is_user_type(m)) { + args[1] = m->desc; + if(cmd_erase(pgm, p, 2, args) < 0) + ret = -1; + } } if(pgm->flush_cache(pgm, p) < 0) @@ -2014,9 +2015,10 @@ static int cmd_factory(const PROGRAMMER *pgm, const AVRPART *p, int argc, const // Reset lock to factory value for(LNODEID ln=lfirst(p->mem); ln; ln=lnext(ln)) - if(mem_is_lock(m = ldata(ln))) - if(fusel_factory(pgm, p, m) < 0) - ret = -1; + if(!avr_mem_exclude(pgm, p, (m = ldata(ln)))) + if(mem_is_lock(m)) + if(fusel_factory(pgm, p, m) < 0) + ret = -1; if(p->factory_fcpu) term_out("after the next reset the part %s have F_CPU = %.3f MHz\n", fuseok? "will": "should", @@ -2247,13 +2249,13 @@ static int cmd_part(const PROGRAMMER *pgm, const AVRPART *p, int argc, const cha } if(onlymem) - avr_mem_display(stdout, p, ""); + avr_mem_display(stdout, pgm, p, ""); else if(onlyvariants) avr_variants_display(stdout, p, ""); else { char *q = str_prog_modes(p->prog_modes); term_out("%s with programming mode%s %s\n", p->desc, strchr(q, ',')? "s": "", q); - avr_mem_display(stdout, p, ""); + avr_mem_display(stdout, pgm, p, ""); avr_variants_display(stdout, p, ""); } lterm_out(""); diff --git a/src/update.c b/src/update.c index 5fad8c06..66929a7f 100644 --- a/src/update.c +++ b/src/update.c @@ -270,16 +270,16 @@ static void ioerror(const char *iotype, const UPDATE *upd) { } // Whether a memory should be returned for ALL: exclude IO/SRAM -static int is_interesting_mem(const AVRPART *p, const AVRMEM *mem) { - return !(mem_is_io(mem) || mem_is_sram(mem)); +static int is_interesting_mem(const PROGRAMMER *pgm, const AVRPART *p, const AVRMEM *mem) { + return !mem_is_io(mem) && !mem_is_sram(mem) && !(pgm && avr_mem_exclude(pgm, p, mem)); } // Whether a memory should be backup-ed: exclude sub-memories -static int is_backup_mem(const AVRPART *p, const AVRMEM *mem) { +static int is_backup_mem(const PROGRAMMER *pgm, const AVRPART *p, const AVRMEM *mem) { return mem_is_in_flash(mem)? mem_is_flash(mem): mem_is_in_sigrow(mem)? mem_is_sigrow(mem): mem_is_in_fuses(mem)? mem_is_fuses(mem) || !avr_locate_fuses(p): - is_interesting_mem(p, mem); + is_interesting_mem(pgm, p, mem); } // Add (not == 0) or subtract (not == 1) a memory from list @@ -296,13 +296,17 @@ static int memadd(AVRMEM **mlist, int nm, int not, AVRMEM *m) { } /* - * Generate a memory list from string mstr and put number of memories into *np. + * Generate a memory list from string mstr, part p and intended programming + * modes pm; then put number of memories into *np. + * * Memory list can be sth like ee,fl,all,-cal,efuse. -mem or /mem removes it * from the list. Normal use is to pass NULL for dry and let the function write * to *np and *rwvsoftfail indicating unknown memories for this part. If dry is * set then -1 will be written to *dry when a generally unknown memory is used. */ -AVRMEM **memory_list(const char *mstr, const AVRPART *p, int *np, int *rwvsoftp, int *dry) { +AVRMEM **memory_list(const char *mstr, const PROGRAMMER *pgm, const AVRPART *p, + int *np, int *rwvsoftp, int *dry) { + int not, nm = (lsize(p->mem) + 1) * ((int) str_numc(mstr, ',') + 1); // Upper limit AVRMEM *m, **umemlist = mmt_malloc(nm*sizeof*umemlist); char *dstr = mmt_strdup(mstr), *s = dstr, *e; @@ -317,11 +321,11 @@ AVRMEM **memory_list(const char *mstr, const AVRPART *p, int *np, int *rwvsoftp, s++; if(str_eq(s, "ALL")) { for(LNODEID lm = lfirst(p->mem); lm; lm = lnext(lm)) - if(is_interesting_mem(p, (m = ldata(lm)))) + if(is_interesting_mem(pgm, p, (m = ldata(lm)))) nm = memadd(umemlist, nm, not, m); } else if(str_eq(s, "all") || str_eq(s, "etc")) { for(LNODEID lm = lfirst(p->mem); lm; lm = lnext(lm)) - if(is_backup_mem(p, (m = ldata(lm)))) + if(is_backup_mem(pgm, p, (m = ldata(lm)))) nm = memadd(umemlist, nm, not, m); } else if(!*s) { // Ignore empty list elements } else { @@ -365,7 +369,7 @@ done: // Returns whether or not the memory list contains a flash memory int memlist_contains_flash(const char *mstr, const AVRPART *p) { int ret = 0, nm = 0; - AVRMEM **mlist = memory_list(mstr, p, &nm, NULL, NULL); + AVRMEM **mlist = memory_list(mstr, NULL, p, &nm, NULL, NULL); for(int i=0; imemstr, p, NULL, NULL, &ret)); + mmt_free(memory_list(upd->memstr, NULL, p, NULL, NULL, &ret)); known = 0; // Necessary to check whether the file is readable? @@ -652,7 +656,7 @@ int do_op(const PROGRAMMER *pgm, const AVRPART *p, const UPDATE *upd, enum updat int allsize, len, maxrlen = 0, ns = 0; if(is_multimem(umstr)) { - umemlist = memory_list(umstr, p, &ns, &rwvsoftfail, NULL); + umemlist = memory_list(umstr, pgm, p, &ns, &rwvsoftfail, NULL); if(!ns) { // ns is number of memories listed pmsg_warning("skipping -U %s:... as no memory in part %s available\n", umstr, p->desc); diff --git a/src/usb_libusb.c b/src/usb_libusb.c index 487810ef..25d6246d 100644 --- a/src/usb_libusb.c +++ b/src/usb_libusb.c @@ -63,8 +63,7 @@ static int usbdev_open(const char *port, union pinfo pinfo, union filedescriptor usb_dev_handle *udev; char *s, serno[64] = {0}; const char *serp; - int i; - int iface; + int i, iface; /* * The syntax for usb devices is defined as: @@ -107,7 +106,7 @@ static int usbdev_open(const char *port, union pinfo pinfo, union filedescriptor dev->descriptor.iSerialNumber, string, sizeof(string)) < 0) { - pmsg_error("cannot read serial number: %s\n", usb_strerror()); + pmsg_warning("reading serial number, %s\n", usb_strerror()); /* * On some systems, libusb appears to have * problems sending control messages. Catch the @@ -115,8 +114,9 @@ static int usbdev_open(const char *port, union pinfo pinfo, union filedescriptor * particular serial number, so we could * continue anyway. */ + cx->usb_access_error = 1; if(*serno) - return -1; /* no chance */ + goto none_matching; // No chance of serno matches strcpy(string, "[unknown]"); } if(serdev) @@ -125,7 +125,7 @@ static int usbdev_open(const char *port, union pinfo pinfo, union filedescriptor dev->descriptor.iProduct, product, sizeof(product)) < 0) { - pmsg_error("cannot read product name: %s\n", usb_strerror()); + pmsg_warning("reading product name, %s\n", usb_strerror()); strcpy(product, "[unnamed product]"); } @@ -186,8 +186,8 @@ static int usbdev_open(const char *port, union pinfo pinfo, union filedescriptor if (usb_set_configuration(udev, dev->config[0].bConfigurationValue)) { - pmsg_warning("unable to set configuration %d: %s\n", - dev->config[0].bConfigurationValue, usb_strerror()); + pmsg_warning("(config %d) %s\n", + dev->config[0].bConfigurationValue, usb_strerror()); /* let's hope it has already been configured */ // goto trynext; } @@ -206,8 +206,8 @@ static int usbdev_open(const char *port, union pinfo pinfo, union filedescriptor #endif if (usb_claim_interface(udev, cx->usb_interface)) { - pmsg_error("unable to claim interface %d: %s\n", - cx->usb_interface, usb_strerror()); + pmsg_warning("(i/face %d) %s\n", cx->usb_interface, usb_strerror()); + cx->usb_access_error = 1; } else { @@ -246,7 +246,7 @@ static int usbdev_open(const char *port, union pinfo pinfo, union filedescriptor } if (fd->usb.rep == 0) { - pmsg_error("cannot find a read endpoint, using 0x%02x\n", + pmsg_warning("cannot find a read endpoint, using 0x%02x\n", USBDEV_BULK_EP_READ_MKII); fd->usb.rep = USBDEV_BULK_EP_READ_MKII; } @@ -267,21 +267,26 @@ static int usbdev_open(const char *port, union pinfo pinfo, union filedescriptor if (pinfo.usbinfo.flags & PINFO_FL_USEHID) { if (usb_control_msg(udev, 0x21, 0x0a /* SET_IDLE */, 0, 0, NULL, 0, 100) < 0) - pmsg_error("SET_IDLE failed\n"); + pmsg_warning("SET_IDLE failed\n"); } return 0; - trynext: + + trynext: usb_close(udev); } else - pmsg_error("cannot open device: %s\n", usb_strerror()); + pmsg_warning("cannot open device: %s\n", usb_strerror()); } } } +none_matching: if ((pinfo.usbinfo.flags & PINFO_FL_SILENT) == 0) - pmsg_notice("%s(): did not find any%s USB device %s (0x%04x:0x%04x)\n", __func__, - *serno? " (matching)": "", port, (unsigned) pinfo.usbinfo.vid, (unsigned)pinfo.usbinfo.pid); + pmsg_error("%s%s USB device %s (%04x:%04x)\n", + cx->usb_access_error? "found but could not access": "did not find any", + *serno && !cx->usb_access_error? " (matching)": "", + port, pinfo.usbinfo.vid, pinfo.usbinfo.pid); + return -1; } diff --git a/src/usbasp.c b/src/usbasp.c index 05beb9a0..e6de2d81 100644 --- a/src/usbasp.c +++ b/src/usbasp.c @@ -450,15 +450,17 @@ static int usbOpenDevice(const PROGRAMMER *pgm, libusb_device_handle **device, i /* we need to open the device in order to query strings */ r = libusb_open(dev, &handle); if (!handle) { - errorCode = USB_ERROR_ACCESS; - pmsg_warning("cannot open USB device: %s\n", errstr(pgm, r)); - continue; + cx->usb_access_error = 1; + errorCode = USB_ERROR_ACCESS; + pmsg_warning("cannot open USB device: %s\n", errstr(pgm, r)); + continue; } errorCode = 0; /* now check whether the names match: */ /* if vendorName not given ignore it (any vendor matches) */ r = libusb_get_string_descriptor_ascii(handle, descriptor.iManufacturer & 0xff, (unsigned char*)string, sizeof(string)); if (r < 0) { + cx->usb_access_error = 1; if ((vendorName != NULL) && (vendorName[0] != 0)) { errorCode = USB_ERROR_IO; pmsg_warning("cannot query manufacturer for device: %s\n", errstr(pgm, r)); @@ -471,6 +473,7 @@ static int usbOpenDevice(const PROGRAMMER *pgm, libusb_device_handle **device, i /* if productName not given ignore it (any product matches) */ r = libusb_get_string_descriptor_ascii(handle, descriptor.iProduct & 0xff, (unsigned char*)string, sizeof(string)); if (r < 0) { + cx->usb_access_error = 1; if ((productName != NULL) && (productName[0] != 0)) { errorCode = USB_ERROR_IO; pmsg_warning("cannot query product for device: %s\n", errstr(pgm, r)); @@ -529,6 +532,7 @@ static int usbOpenDevice(const PROGRAMMER *pgm, usb_dev_handle **device, int ven /* we need to open the device in order to query strings */ handle = usb_open(dev); if(!handle){ + cx->usb_access_error = 1; errorCode = USB_ERROR_ACCESS; pmsg_warning("cannot open USB device: %s\n", usb_strerror()); continue; @@ -539,9 +543,10 @@ static int usbOpenDevice(const PROGRAMMER *pgm, usb_dev_handle **device, int ven len = usb_get_string_simple(handle, dev->descriptor.iManufacturer, string, sizeof(string)); if(len < 0){ + cx->usb_access_error = 1; if ((vendorName != NULL) && (vendorName[0] != 0)) { - errorCode = USB_ERROR_IO; - pmsg_warning("cannot query manufacturer for device: %s\n", usb_strerror()); + errorCode = USB_ERROR_IO; + pmsg_warning("cannot query manufacturer for device: %s\n", usb_strerror()); } } else { pmsg_notice2("seen device from vendor >%s<\n", string); @@ -552,6 +557,7 @@ static int usbOpenDevice(const PROGRAMMER *pgm, usb_dev_handle **device, int ven len = usb_get_string_simple(handle, dev->descriptor.iProduct, string, sizeof(string)); if(len < 0){ + cx->usb_access_error = 1; if ((productName != NULL) && (productName[0] != 0)) { errorCode = USB_ERROR_IO; pmsg_warning("cannot query product for device: %s\n", usb_strerror()); @@ -604,22 +610,11 @@ static int usbasp_open(PROGRAMMER *pgm, const char *port) { } vid = pgm->usbvid? pgm->usbvid: USBASP_SHARED_VID; if(usbOpenDevice(pgm, &PDATA(pgm)->usbhandle, vid, pgm->usbvendor, pid, pgm->usbproduct, port) != 0) { - /* try alternatives */ if(str_eq(pgmid, "usbasp")) { - /* for id usbasp autodetect some variants */ - if(str_caseeq(port, "nibobee")) { - pmsg_error("using -C usbasp -P nibobee is deprecated, use -C nibobee instead\n"); - if(usbOpenDevice(pgm, &PDATA(pgm)->usbhandle, USBASP_NIBOBEE_VID, "www.nicai-systems.com", - USBASP_NIBOBEE_PID, "NIBObee", port) != 0) { - pmsg_error("cannot find USB device NIBObee with vid=0x%x pid=0x%x\n", - USBASP_NIBOBEE_VID, USBASP_NIBOBEE_PID); - return -1; - } - return 0; - } /* check if device with old VID/PID is available */ if(usbOpenDevice(pgm, &PDATA(pgm)->usbhandle, USBASP_OLD_VID, "www.fischl.de", USBASP_OLD_PID, "USBasp", port) == 0) { + cx->usb_access_error = 0; /* found USBasp with old IDs */ pmsg_error("found USB device USBasp with old VID/PID; please update firmware of USBasp\n"); return 0; diff --git a/src/usbtiny.c b/src/usbtiny.c index cb5b3fd0..a5c53eba 100644 --- a/src/usbtiny.c +++ b/src/usbtiny.c @@ -86,9 +86,9 @@ static void usbtiny_teardown(PROGRAMMER *pgm) { } // Wrapper for simple usb_control_msg messages -static int usb_control (const PROGRAMMER *pgm, - unsigned int requestid, unsigned int val, unsigned int index ) -{ +static int usb_control(const PROGRAMMER *pgm, + unsigned int requestid, unsigned int val, unsigned int index, int silent) { + int nbytes; nbytes = usb_control_msg( PDATA(pgm)->usb_handle, USB_ENDPOINT_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, @@ -97,8 +97,11 @@ static int usb_control (const PROGRAMMER *pgm, NULL, 0, // no data buffer in control message USB_TIMEOUT ); // default timeout if(nbytes < 0){ - msg_error("\n"); - pmsg_error("%s\n", usb_strerror()); + cx->usb_access_error = 1; + if(!silent) { + msg_error("\n"); + pmsg_error("%s\n", usb_strerror()); + } return -1; } @@ -408,7 +411,7 @@ static int usbtiny_set_sck_period (const PROGRAMMER *pgm, double v) { // send the command to the usbtiny device. // MEME: for at90's fix resetstate? - if (usb_control(pgm, USBTINY_POWERUP, PDATA(pgm)->sck_period, RESET_LOW) < 0) + if (usb_control(pgm, USBTINY_POWERUP, PDATA(pgm)->sck_period, RESET_LOW, 0) < 0) return -1; // with the new speed, we'll have to update how much data we send per usb transfer @@ -430,7 +433,7 @@ static int usbtiny_initialize (const PROGRAMMER *pgm, const AVRPART *p ) { PDATA(pgm)->sck_period = SCK_DEFAULT; pmsg_notice("using SCK period of %d usec\n", PDATA(pgm)->sck_period ); if (usb_control(pgm, USBTINY_POWERUP, - PDATA(pgm)->sck_period, RESET_LOW ) < 0) + PDATA(pgm)->sck_period, RESET_LOW, 0) < 0) return -1; usbtiny_set_chunk_size(pgm, PDATA(pgm)->sck_period); } @@ -471,10 +474,8 @@ static int usbtiny_initialize (const PROGRAMMER *pgm, const AVRPART *p ) { if (pgm->program_enable(pgm, p) >= 0) break; // no response, RESET and try again - if (usb_control(pgm, USBTINY_POWERUP, - PDATA(pgm)->sck_period, RESET_HIGH) < 0 || - usb_control(pgm, USBTINY_POWERUP, - PDATA(pgm)->sck_period, RESET_LOW) < 0) + if(usb_control(pgm, USBTINY_POWERUP, PDATA(pgm)->sck_period, RESET_HIGH, 0) < 0 || + usb_control(pgm, USBTINY_POWERUP, PDATA(pgm)->sck_period, RESET_LOW, 0) < 0) return -1; usleep(50000); } @@ -486,10 +487,8 @@ static int usbtiny_initialize (const PROGRAMMER *pgm, const AVRPART *p ) { static int usbtiny_setpin(const PROGRAMMER *pgm, int pinfunc, int value) { /* USBtiny is not a bit bang device, but it can set RESET */ if(pinfunc == PIN_AVR_RESET) { - if (usb_control(pgm, USBTINY_POWERUP, - PDATA(pgm)->sck_period, value ? RESET_HIGH : RESET_LOW) < 0) { + if(usb_control(pgm, USBTINY_POWERUP, PDATA(pgm)->sck_period, value? RESET_HIGH: RESET_LOW, 0) < 0) return -1; - } usleep(50000); return 0; } @@ -498,10 +497,9 @@ static int usbtiny_setpin(const PROGRAMMER *pgm, int pinfunc, int value) { /* Tell the USBtiny to release the output pins, etc */ static void usbtiny_powerdown(const PROGRAMMER *pgm) { - if (!PDATA(pgm)->usb_handle) { + if (!PDATA(pgm)->usb_handle) return; // wasn't connected in the first place - } - usb_control(pgm, USBTINY_POWERDOWN, 0, 0); // Send USB control command to device + usb_control(pgm, USBTINY_POWERDOWN, 0, 0, 1); } /* Send a 4-byte SPI command to the USBtinyISP for execution @@ -718,7 +716,7 @@ static int usbtiny_paged_write(const PROGRAMMER *pgm, const AVRPART *p, const AV unsigned int poll_value = (m->readback[1] << 8) | m->readback[0]; if(!poll_value) poll_value = 0xffff; - if (usb_control(pgm, USBTINY_POLL_BYTES, poll_value, 0 ) < 0) + if(usb_control(pgm, USBTINY_POLL_BYTES, poll_value, 0, 0) < 0) return -1; delay = m->max_write_delay; } diff --git a/tools/test8 b/tools/test8 new file mode 100755 index 00000000..51601e05 --- /dev/null +++ b/tools/test8 @@ -0,0 +1,87 @@ +#!/usr/bin/env bash + +# Published under GNU General Public License, version 3 (GPL-3.0) +# Author Stefan Rueger, 2024 + +progname=$(basename "$0") +adopts=() +mem=ALL +init=-1 +rand=-1 + +Usage() { +cat <] +Function: test AVRDUDE for v 8.0 release with -c programmer -p part; + also leaves a file bak-- use avrdude -c dryrun -xinit= to initialiase part and exit + -r use avrdude -c dryrun -xrandom= to initialiase part and exit + -a pass avrdude option through to avrdude test commands + -m use memory list instead of ALL + +Examples: + - Prepare a part with non-trivial random content + $ test8 -r1 usbasp t13a + + - Then test ... + $ test8 avrisp2 t13a + $ test8 snap_isp t13a +END +} + +while getopts ":i:r:a:m:" opt; do + case ${opt} in + i) init=0; [[ ! -z "$OPTARG" ]] && init="$OPTARG" + ;; + r) rand=0; [[ ! -z "$OPTARG" ]] && rand="$OPTARG" + ;; + a) if [[ ! -z "$OPTARG" ]]; then adopts+=("$OPTARG"); fi + ;; + m) if [[ ! -z "$OPTARG" ]]; then mem="$OPTARG"; fi + ;; + --) shift; + break + ;; + \?) echo "$progname: invalid option -$OPTARG" 1>&2 + Usage; exit 1 + ;; + : ) echo "$progname: invalid option -$OPTARG requires an argument" 1>&2 + Usage; exit 1 + ;; + esac +done +shift $((OPTIND -1)) + + +if [ $# -ne 2 ]; then + why=missing; [ $# -gt 2 ] && why="too many" + echo $progname: $why arguments + Usage + exit 1 +fi + +###### +# Generated backup file + +f="bak-$1-$2.hex:I" + +###### +# Initialise and exit if requested by -i or -r + +if [[ $init -gt -1 || $rand -gt -1 ]]; then + how="init=$init"; [ $rand -gt -1 ] && how="random=$rand" + avrdude -qqc dryrun -p $2 -U $mem:r:$f -x $how + avrdude -c $1 -p $2 -U $mem:w:$f + echo $progname: $2 initialsed + exit 0 +fi + +###### +# Actual test + +if ! avrdude "${adopts[@]}" -c $1 -p $2 -D -U$mem:r:$f -T "fact reset" -U$mem:w:$f -U$mem:v:$f; then + echo ------------------------------- + echo Re-running to create error logs + avrdude "${adopts[@]}" -vvv -c $1 -p $2 -D -U$mem:r:$f -T "fact reset" -U$mem:w:$f -U$mem:v:$f -llog-$1-$2.txt +fi