From 46c7bf38ec48cc72fd64c55e60762b44c43e92ea Mon Sep 17 00:00:00 2001 From: Joerg Wunsch Date: Thu, 25 Aug 2011 16:12:30 +0000 Subject: [PATCH] Submitted by Doug Springer, based on work by Wolfgang Moser, Ville Voipio, Hannes Weisbach patch #7486: Patch to add FT2232C/D, FT2232H, FT4232H, usbvid, usbpid, usbdev for USB support - Based on #7062 * avrftdi.c: New file. * avrftdi.h: (Ditto.) * configure.ac: Add check for libftdi. * config_gram.y: Add AVRFTDI and per-programmer USB string keywords. * lexer.l: (Ditto.) * avrdude.conf.in: Add avrftdi and 2232HIO programmers. * pgm.h: Add USB parameters. * Makefile.am: Add avrftdi.c and avrftdi.h. * AUTHORS: Mention the new authors. * avrdude.1: Document the changes. git-svn-id: svn://svn.savannah.nongnu.org/avrdude/trunk/avrdude@979 81a1dc3b-b13d-400b-aceb-764788c761c2 --- AUTHORS | 5 +- ChangeLog | 19 + Makefile.am | 4 +- NEWS | 1 + avrdude.1 | 17 +- avrdude.conf.in | 75 ++++ avrftdi.c | 1079 ++++++++++++++++++++++++++++++++++++++++++++++ avrftdi.h | 56 +++ config_gram.y | 56 +++ configure.ac | 9 +- doc/avrdude.texi | 7 +- lexer.l | 7 + pgm.h | 4 + 13 files changed, 1332 insertions(+), 7 deletions(-) create mode 100644 avrftdi.c create mode 100644 avrftdi.h diff --git a/AUTHORS b/AUTHORS index ed8aef03..fa37909e 100644 --- a/AUTHORS +++ b/AUTHORS @@ -16,6 +16,9 @@ Contributors: David Hoerl Michal Ludvig Darell Tan - + Wolfgang Moser + Ville Voipio + Hannes Weisbach + Doug Springer For minor contributions, please see the ChangeLog files. diff --git a/ChangeLog b/ChangeLog index 2c0fe24e..5c5e24d1 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,22 @@ +2011-08-25 Joerg Wunsch + + Submitted by Doug Springer, based on work by + Wolfgang Moser, Ville Voipio, Hannes Weisbach + patch #7486: Patch to add FT2232C/D, FT2232H, FT4232H, + usbvid, usbpid, usbdev for USB support - Based on #7062 + * avrftdi.c: New file. + * avrftdi.h: (Ditto.) + * configure.ac: Add check for libftdi. + * config_gram.y: Add AVRFTDI and per-programmer USB string + keywords. + * lexer.l: (Ditto.) + * avrdude.conf.in: Add avrftdi and 2232HIO programmers. + * pgm.h: Add USB parameters. + * Makefile.am: Add avrftdi.c and avrftdi.h. + * AUTHORS: Mention the new authors. + * avrdude.1: Document the changes. + * doc/avrdude.texi: (Ditto.) + 2011-08-23 Joerg Wunsch bug #29585: Fix license diff --git a/Makefile.am b/Makefile.am index efc48eb2..546939a6 100644 --- a/Makefile.am +++ b/Makefile.am @@ -56,7 +56,7 @@ avrdude_CFLAGS = @ENABLE_WARNINGS@ libavrdude_a_CFLAGS = @ENABLE_WARNINGS@ -avrdude_LDADD = $(top_builddir)/$(noinst_LIBRARIES) @LIBUSB@ @LIBUSB_1_0@ @LIBHID@ -lm +avrdude_LDADD = $(top_builddir)/$(noinst_LIBRARIES) @LIBUSB@ @LIBUSB_1_0@ @LIBFTDI@ @LIBHID@ -lm bin_PROGRAMS = avrdude @@ -87,6 +87,8 @@ libavrdude_a_SOURCES = \ avr910.c \ avr910.h \ avrdude.h \ + avrftdi.c \ + avrftdi.h \ avrpart.c \ avrpart.h \ bitbang.c \ diff --git a/NEWS b/NEWS index b3a86126..2fa835d0 100644 --- a/NEWS +++ b/NEWS @@ -15,6 +15,7 @@ Current: * New programmers supported: - TPI programming through bitbang programmers (both, serial and parallel ones) + - FT2232 (and relatives) based programmers (MPSSE bitbang mode) * Bugfixes diff --git a/avrdude.1 b/avrdude.1 index c168819b..a111970e 100644 --- a/avrdude.1 +++ b/avrdude.1 @@ -148,11 +148,16 @@ option might be required to achieve a stable ISP communication. For ATxmega devices, the AVR Dragon is supported in PDI mode, provided it has a firmware version of at least 6.11 (decimal). .Pp -The USBasp ISP and USBtinyISP adapters are also supported, provided +The avrftdi, USBasp ISP and USBtinyISP adapters are also supported, provided .Nm avrdude has been compiled with libusb support. -They both feature simple firmware-only USB implementations, running on -an ATmega8 (or ATmega88), or ATtiny2313, respectively. +USBasp ISP and USBtinyISP both feature simple firmware-only USB implementations, +running on an ATmega8 (or ATmega88), or ATtiny2313, respectively. If libftdi has +has been compiled in +.Nm avrdude , +the avrftdi device adds support for many programmers using FTDI's 2232C/D/H +and 4232H parts running in MPSSE mode, which hard-codes (in the chip) +SCK to bit 1, MOSI to bit 2, and MISO to bit 3. Reset is usually bit 4. .Pp Input files can be provided, and output files can be written in different file formats, such as raw binary files containing the data @@ -1041,3 +1046,9 @@ This also applies to the STK500 and STK600 in parallel programming mode. The USBasp and USBtinyISP drivers do not offer any option to distinguish multiple devices connected simultaneously, so effectively only a single device is supported. +.Pp +The avrftdi driver allows to select specific devices using any combination of vid,pid +serial number (usbsn) vendor description (usbvendoror part description (usbproduct) +as seen with lsusb or whatever tool used to view USB device information. Multiple +devices can be on the bus at the same time. For the H parts, which have multiple MPSSE +interfaces, the interface can also be selected. It defaults to interface 'A'. diff --git a/avrdude.conf.in b/avrdude.conf.in index 2033037c..c7c718b8 100644 --- a/avrdude.conf.in +++ b/avrdude.conf.in @@ -32,6 +32,14 @@ # rdyled = ; # pin number # pgmled = ; # pin number # vfyled = ; # pin number +# usbvid = ; # USB VID (Vendor ID) +# usbpid = ; # USB PID (Product ID) +# usbdev = ; # USB interface or other device info +# usbvendor = ; # USB Vendor Name +# usbproduct = ; # USB Product Name +# usbsn = ; # USB Serial Number +# +# To invert a bit, use = ~ , the spaces are important. # ; # # part @@ -319,6 +327,73 @@ programmer desc = "Arduino"; type = arduino; ; +# this will interface with the chips on these programmers: +# +# http://real.kiev.ua/old/avreal/en/adapters +# http://www.amontec.com/jtagkey.shtml, jtagkey-tiny.shtml +# http://www.olimex.com/dev/arm-usb-ocd.html, arm-usb-tiny.html +# http://www.ethernut.de/en/hardware/turtelizer/index.html +# http://elk.informatik.fh-augsburg.de/hhweb/doc/openocd/usbjtag/usbjtag.html +# http://dangerousprototypes.com/docs/FT2232_breakout_board +# http://www.ftdichip.com/Products/Modules/DLPModules.htm,DLP-2232*,DLP-USB1232H +# http://flashrom.org/FT2232SPI_Programmer +# +# The drivers will look for a specific device and use the first one found. +# If you have mulitple devices, then look for unique information (like SN) +# And fill that in here. + +programmer + id = "avrftdi"; + desc = "FT2232D based generic programmer"; + type = avrftdi; + usbvid = 0x0403; + usbpid = 0x6010; + usbvendor = ""; + usbproduct = ""; + usbdev = "A"; + usbsn = ""; +#ISP-signals - lower ACBUS-Nibble (default) + reset = 4; + sck = 1; + mosi = 2; + miso = 3; +#LED SIGNALs - higher ACBUS-Nibble +# errled = 5; +# rdyled = 6; +# pgmled = 7; +# vfyled = 8; +#Buffer Signal - ADBUS - Nibble +# buff = 9; +; +# This is an implementation of the above with a buffer IC (74AC244) and +# 4 LEDs directly attached, active low. The buff and reset pins are +# understood (by avrdude) to be active low, so there's no +# need to invert the bits. +programmer + id = "2232HIO"; + desc = "FT2232H based generic programmer"; + type = avrftdi; + usbvid = 0x0403; +# Note: This PID is reserved for generic H devices and +# should be programmed into the EEPROM +# usbpid = 0x8A48; + usbpid = 0x6010; + usbdev = "A"; + usbvendor = ""; + usbproduct = ""; + usbsn = ""; +#ISP-signals + reset = 4; + sck = 1; + mosi = 2; + miso = 3; + buff = 5; +#LED SIGNALs + errled = ~ 12; + rdyled = ~ 15; + pgmled = ~ 14; + vfyled = ~ 13; +; programmer id = "avrisp"; diff --git a/avrftdi.c b/avrftdi.c new file mode 100644 index 00000000..37d883b6 --- /dev/null +++ b/avrftdi.c @@ -0,0 +1,1079 @@ +/* + * avrftdi - extension for avrdude, Wolfgang Moser, Ville Voipio + * Copyright (C) 2011 Hannes Weisbach, Doug Springer + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* $Id$ */ +/* + * Interface to the MPSSE Engine of FTDI Chips using libftdi. + */ +#include "ac_cfg.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "avrdude.h" +#include "avr.h" +#include "pgm.h" +#include "avrftdi.h" + +#ifdef HAVE_LIBUSB +#ifdef HAVE_LIBFTDI + +#include +#include + +/* This is for running the code without having a FTDI-device. + * The generated code is useless! For debugging purposes only. + * This should never be defined, unless you know what you are + * doing. + * If you think you know what you are doing: YOU DONT! + */ +//#define DRYRUN + +static struct ftdi_context ftdic; +static uint16_t pin_value, pin_direction, pin_inversion, led_mask; +static int type; /**type is bcdDevice. C/D is 0x500 H is 0x700 4H is 0x800*/ +static int ftype; /** is from FTDI. Use TYPE_2232C, TYPE_2232H, or TYPE_4232H*/ + +static void buf_dump(unsigned char *buf, int len, char *desc, + int offset, int width) +{ + int i; + fprintf(stderr, "%s begin:\n", desc); + for (i = 0; i < offset; i++) + fprintf(stderr, "%02x ", buf[i]); + fprintf(stderr, "\n"); + for (i++; i <= len; i++) { + fprintf(stderr, "%02x ", buf[i-1]); + if((i-offset) != 0 && (i-offset)%width == 0) + fprintf(stderr, "\n"); + } + fprintf(stderr, "%s end\n", desc); +} + +static int set_frequency(uint32_t freq) +{ + uint32_t divisor; + uint8_t buf[3]; + + /* divisor on 6000000 / freq - 1 */ + divisor = (6000000 / freq) - 1; + if (divisor < 0) { + fprintf(stderr, + "%s failure: Frequency too high (%u > 6 MHz)\n", + progname, freq); + fprintf(stderr, + "resetting Frequency to 6MHz\n"); + divisor = 0; + } + + if (divisor > 65535) { + fprintf(stderr, + "%s failure: Frequency too low (%u < 91.553 Hz)\n", + progname, freq); + fprintf(stderr, + "resetting Frequency to 91.553Hz\n"); + divisor = 65535; + } + + if(verbose) + fprintf(stderr, + "%s info: clock divisor: 0x%04x\n", + progname, divisor); + + buf[0] = 0x86; + buf[1] = (uint8_t)(divisor & 0xff); + buf[2] = (uint8_t)((divisor >> 8) & 0xff); + +#ifndef DRYRUN + E(ftdi_write_data(&ftdic, buf, 3) < 0); +#endif + + return 0; +} + +/* Add a single pin (by pin number) to the pin masks (or to pins), + * update pinmask[pinfunc] */ +static int add_pin(PROGRAMMER *pgm, int pinfunc) +{ + int pin, inversion_mask, mlim; + + pin = pgm->pinno[pinfunc]; + if (verbose) + fprintf(stderr, + "add_pin: %d: bit 0x%04x inv=0x%04x\n", + pinfunc, pin, + (pin & PIN_INVERSE)? (1<< ((pin&PIN_MASK) - 1)): 0); + + /* non-existent definitions, go away */ + if (pin == 0) + return 0; + + /* see if pin should be inverted */ + if(pin & PIN_INVERSE) { + pin &= PIN_MASK; + inversion_mask = 1 << (pin - 1); + } else { + inversion_mask = 0; + } + if(TYPE_4232H == ftype) + mlim=7; + else if(TYPE_2232C==ftype) + mlim=11; + else if(TYPE_2232H == ftype) + mlim=15; + else{ + printf("Unknown type %d (0x%x)\n",ftype,ftype); + mlim=15; + } + /* check that the pin number is in range */ + if (pin > mlim) { + fprintf(stderr, + "%s failure: invalid pin definition (pin no > %d) in config file\n", + progname, mlim); + fprintf(stderr, + "pin function no %d, pin no: 0x%x\n", + pinfunc, pin); + return -1; + } + + /* create the mask and check that the pin is available */ + if (pin_direction & (1 << (pin -1)) ) { + fprintf(stderr, + "%s failure: pin %d has two definitions in config file\n", + progname, pin); + return -1; + } else { + pin_direction |= (1 << (pin - 1)); + pin_inversion |= inversion_mask; + } + if(PIN_LED_ERR == pinfunc || + PIN_LED_VFY == pinfunc || + PIN_LED_RDY == pinfunc || + PIN_LED_PGM == pinfunc) { + led_mask|=(1 << (pin - 1)); + } + + return 0; +} + +/* Add pins by pin mask */ + +static int add_pins(PROGRAMMER *pgm, int pinfunc) +{ + int i, pin, mlim; + uint32_t mask, inversion_mask=0; + + pin = pgm->pinno[pinfunc]; + + if(pin & PIN_INVERSE){ + pin &= PIN_MASK; + inversion_mask = pin >>1; + } + pin >>= 1; + if (verbose) + fprintf(stderr, + "add_pins: %d: 0x%04x, inv=0x%04x\n", + pinfunc, pin, inversion_mask); + mask = pin; + if (TYPE_4232H == ftype) + mlim = 8; + else if (TYPE_2232C == ftype) + mlim = 12; + else if (TYPE_2232H == ftype) + mlim = 16; + else{ + printf("Unknown type %d (0x%x)\n", + ftype, ftype); + mlim = 16; + } + if (mask >= 1 << mlim) { + fprintf(stderr, + "%s failure: pin list has pins out of range (%x>%x): ", + progname, mask, 1 << mlim); + mask &= ~(1 << mlim) - 1; + } + else if (mask & pin_direction) { + fprintf(stderr, + "%s failure: conflicting pins in pin list: ", + progname); + mask &= pin_direction; + } + else { + pin_direction |= (uint16_t)mask; + pin_inversion |= inversion_mask; + return 0; + } + + /* print the list of pins, if needed */ + i = 0; + while (mask > 1) { + if (mask & 1) + fprintf(stderr, "%d, ", i); + mask >>= 1; + i++; + } + if (mask > 0) + fprintf(stderr, "%d\n", i); + return -1; +} + + +static int write_flush(void) +{ + unsigned char buf[6]; + if(verbose > 2) + fprintf(stderr, + "%s info: direction: 0x%04x, value: 0x%04x, inversion: 0x%04x\n", + progname, pin_direction, pin_value, pin_inversion); + + buf[0] = 0x80; + buf[1] = pin_value & 0xff; + buf[2] = pin_direction & 0xff; + buf[3] = 0x82; + buf[4] = (pin_value >> 8) & 0xff; + buf[5] = (pin_direction >> 8) & 0xff; + +#ifndef DRYRUN + E(ftdi_write_data(&ftdic, buf, 6) != 6); + +#endif + + if (verbose > 3) + printf("FTDI LOG: %02x %02x %02x %02x %02x %02x\n", + buf[0], buf[1], buf[2], buf[3], buf[4], buf[5]); + + /* we need to flush here, because set_pin is used as reset. + * if we want to sleep reset periods, we must be certain the + * avr has got the reset signal when we start sleeping. + * (it may be stuck in the USB stack or some USB hub) + */ + E(ftdi_usb_purge_buffers(&ftdic)); + + return 0; + +} + +/* this function sets or clears a GPIO pin */ +static int set_pin(int pin, int value) +{ + int bit; + uint16_t tval; + if (0 == pin){ + if(verbose > 2) + fprintf(stderr, + "%s info: Pin is zero val %d!\n", + progname, value); + return 1; + } + --pin; + bit= 1 << (pin); + if (pin_inversion & bit) { + value = !value; + } + if (value) + value = bit; + + if (verbose > 1) + fprintf(stderr, + "%s info: pin %04x bit %04x value 0x%04x\n", + progname, pin + 1, bit, value); + /* set bits depending on value */ + /*pin_value ^= (-value ^ pin_value) & (1 << (pin - 1)); */ + tval = (pin_value & (~bit)) | value; + if (tval != pin_value) { + pin_value = tval; + return write_flush(); + } else if (verbose > 1) + fprintf(stderr, "SameVal\n"); + return 0; + +} + +/* this function sets or clears one or more GPIO pin these are bit-mapped */ +static int set_pins(int pin, int value) +{ + if (0 == pin) { + if(verbose > 2) + fprintf(stderr,"%s info: Pins is zero!\n",progname); + return 1; + } + pin >>=1; + if (pin_inversion & pin) { + value = !value; + } + if (value) + value = pin; + + if (verbose) + fprintf(stderr, + "%s info: pin %04x value %d\n", + progname, pin, value); + /* set bits depending on value */ + /*pin_value ^= (-value ^ pin_value) & (1 << (pin - 1)); */ + pin_value = (pin_value & (~pin)) | value; + return write_flush(); +} + +/* these functions are callbacks, which go into the + * PROGRAMMER data structure ("optional functions") + */ +static int set_led_pgm(struct programmer_t * pgm, int value) +{ + return set_pin(pgm->pinno[PIN_LED_PGM], value); +} + +static int set_led_rdy(struct programmer_t * pgm, int value) +{ + return set_pin(pgm->pinno[PIN_LED_RDY], value); +} + +static int set_led_err(struct programmer_t * pgm, int value) +{ + return set_pin(pgm->pinno[PIN_LED_ERR], value); +} + +static int set_led_vfy(struct programmer_t * pgm, int value) +{ + return set_pin(pgm->pinno[PIN_LED_VFY], value); +} + +static int avrftdi_transmit(unsigned char mode, unsigned char *cmd, + unsigned char *data, int buf_size) +{ + int k = 0; + int n; + unsigned char buf[4 + buf_size]; + + if (mode & TX) { + buf[0] = mode; + buf[1] = ((buf_size - 1) & 0xff); + buf[2] = (((buf_size - 1) >> 8) & 0xff); + + memcpy(buf + 3, cmd, buf_size); + buf[buf_size + 3] = 0x87; + +#ifndef DRYRUN + E(ftdi_write_data(&ftdic, buf, buf_size + 4) != buf_size + 4); +#endif + } + + if (mode & RX) { + memset(buf, 0, sizeof(buf)); + do { +#ifndef DRYRUN + n = ftdi_read_data(&ftdic, buf + k, buf_size - k); + E(n < 0); +#else + n = buf_size - k; +#endif + k += n; + } while (k < buf_size); + + memcpy(data, buf, buf_size); + } + + return k; +} + +static int avrftdi_open(PROGRAMMER * pgm, char *port) +{ + int vid, pid, interface, snfound; + char serial[255], *foundsn; + struct ftdi_device_list* devlist; + struct ftdi_device_list* devlist_ptr; + struct usb_device *found_dev; + /* use vid/pid in following priority: config, + * defaults. cmd-line is currently not supported */ + type = 0; + snfound = 0; + foundsn = NULL; + + if (pgm->usbvid) + vid = pgm->usbvid; + else + vid = 0x0403; + + if (pgm->usbpid) + pid = pgm->usbpid; + else + pid = 0x6010; + + if (0 == pgm->usbsn[0]) /* we don't care about SN. Use first avail. */ + snfound = 1; + + if (pgm->usbdev[0] == 'a' || pgm->usbdev[0] == 'A') + interface = INTERFACE_A; + else if (pgm->usbdev[0] == 'b' || pgm->usbdev[0] == 'B') + interface = INTERFACE_B; + else { + fprintf(stderr, + "%s: Invalid interface '%s'. Setting to Interface A\n", + progname, pgm->usbdev); + interface = INTERFACE_A; + } +#ifndef DRYRUN + E(ftdi_init(&ftdic) < 0); + found_dev = NULL; + if (ftdi_usb_find_all(&ftdic, &devlist, vid, pid)) { + devlist_ptr = devlist; + do { + ftdi_usb_get_strings(&ftdic, devlist_ptr->dev, + NULL, 0, NULL, 0, serial, 255); + + if (verbose) + fprintf(stderr, + "%s: device: %s, serial number: %s type 0x%04x found\n", + progname, devlist_ptr->dev->filename, + serial, devlist_ptr->dev->descriptor.bcdDevice); + + if (!snfound) { + if (strcmp(pgm->usbsn, serial) == 0){ + foundsn = strdup(serial); + snfound = 1; + found_dev = devlist_ptr->dev; + type = devlist_ptr->dev->descriptor.bcdDevice; + } + }else { + if (0 == type) /**we assume it will attach to first found. */ + type = devlist_ptr->dev->descriptor.bcdDevice; + if (NULL == found_dev) + found_dev = devlist_ptr->dev; + if (NULL == foundsn) + foundsn = strdup(serial); + } + memset(serial, 0, 255); + devlist_ptr = devlist_ptr->next; + } while (devlist_ptr); + } else { + fprintf(stderr, + "%s: No devices with Vendor-ID:Product-ID %04x:%04x found.\n", + progname, vid, pid); + ftdi_list_free(&devlist); + return -1; + } + if (!snfound) { + fprintf(stderr, + "%s: No devices with VID:PID %04x:%04x and SN '%s' found.\n", + progname, vid, pid, pgm->usbsn); + ftdi_list_free(&devlist); + return -1; + } + if (verbose) { + fprintf(stderr, + "%s: Using device VID:PID %04x:%04x type 0x%04x(", + progname, vid, pid, type); + switch (type) { + case TYPE_C_D: + fprintf(stderr,"C/D"); break; + case TYPE_H: + fprintf(stderr,"H"); break; + case TYPE_4H: + fprintf(stderr,"4H"); break; + default: + fprintf(stderr,"unknown %04x",type); break; + } + + fprintf(stderr,") and SN '%s'.\n", foundsn); + } + if (type == TYPE_C_D && INTERFACE_B == interface){ + fprintf(stderr, + "%s: Type C/D found. Setting interface to A\n", + progname); + interface = INTERFACE_A; + } + /*must be A for mpsse if C/D, can be A/B for H */ + if (verbose) + fprintf(stderr, + "%s: Using USB Interface %c\n", + progname, INTERFACE_A == interface? 'A': 'B'); + free(foundsn); + E(ftdi_set_interface(&ftdic, interface) < 0); + E(ftdi_usb_open_dev(&ftdic,found_dev) <0); +/* E(ftdi_usb_open_desc(&ftdic, vid,pid,NULL,0==pgm->usbsn[0]?NULL:pgm->usbsn) < 0); */ + ftype=ftdic.type; +#endif + + + if (SCK != (1 << (pgm->pinno[PIN_AVR_SCK] - 1)) + || SDO != (1 << (pgm->pinno[PIN_AVR_MOSI] - 1)) + || SDI != (1 << (pgm->pinno[PIN_AVR_MISO] - 1))) { + fprintf(stderr, + "%s failure: pinning for FTDI MPSSE must be:\n" + "\tSCK: 1, SDO: 2, SDI: 3(is: %d,%d,%d)\n", + progname, + pgm->pinno[PIN_AVR_SCK], + pgm->pinno[PIN_AVR_MOSI], + pgm->pinno[PIN_AVR_MISO]); + fprintf(stderr, "Setting pins accordingly ...\n"); + pgm->pinno[PIN_AVR_SCK] = 1; + pgm->pinno[PIN_AVR_MOSI] = 2; + pgm->pinno[PIN_AVR_MISO] = 3; + + } + if(verbose) + fprintf(stderr, + "%s info: reset pin value: %x\n", + progname, pgm->pinno[PIN_AVR_RESET]-1); + if (pgm->pinno[PIN_AVR_RESET] < 4 || pgm->pinno[PIN_AVR_RESET] == 0) { + fprintf(stderr, + "%s failure: RESET pin clashes with data pin or is not set.\n", + progname); + fprintf(stderr, "Setting to default-value 4\n"); + pgm->pinno[PIN_AVR_RESET] = 4; + } + /**sync our internal state with the chip */ + pin_direction = 0; + pin_value = 0; + write_flush(); + pin_direction = (0x3 | (1 << (pgm->pinno[PIN_AVR_RESET] - 1))); + + /* gather the rest of the pins */ + if (add_pins(pgm, PPI_AVR_VCC)) return -1; + if (add_pins(pgm, PPI_AVR_BUFF)) return -1; + if (add_pin(pgm, PIN_LED_ERR)) return -1; + if (add_pin(pgm, PIN_LED_RDY)) return -1; + if (add_pin(pgm, PIN_LED_PGM)) return -1; + if (add_pin(pgm, PIN_LED_VFY)) return -1; +#ifndef DRYRUN + E(ftdi_set_bitmode(&ftdic, pin_direction & 0xff, BITMODE_MPSSE) < 0); /*set SPI */ +#endif + if (verbose > 1) { + fprintf(stderr, "pin direction mask: %04x\n", pin_direction); + fprintf(stderr, "pin value mask: %04x\n", pin_value); + } + + if (pgm->baudrate) { + set_frequency(pgm->baudrate); + } else if(pgm->bitclock) { + set_frequency((uint32_t)(1.0f/pgm->bitclock)); + } else { + set_frequency(pgm->baudrate ? pgm->baudrate : 150000); + } + /**set the ready LED, if we have one .. and set our direction up */ + set_led_rdy(pgm,0); + set_led_rdy(pgm,1); + return 0; +} + +static void avrftdi_close(PROGRAMMER * pgm) +{ + if(ftdic.usb_dev) { + set_pins(pgm->pinno[PPI_AVR_BUFF], ON); + set_pin(pgm->pinno[PIN_AVR_RESET], ON); + /**Stop driving the pins - except for the LEDs */ + if (verbose > 1) + fprintf(stderr, + "LED Mask=0x%04x value =0x%04x &=0x%04x\n", + led_mask, pin_value, led_mask & pin_value); + pin_direction = led_mask; + pin_value &= led_mask; + write_flush(); +#ifndef DRYRUN + E_VOID(ftdi_usb_close(&ftdic)); +#endif + } + +#ifndef DRYRUN + ftdi_deinit(&ftdic); +#endif + + return; +} + + +static int avrftdi_initialize(PROGRAMMER * pgm, AVRPART * p) +{ + set_pin(pgm->pinno[PIN_AVR_RESET], OFF); + set_pins(pgm->pinno[PPI_AVR_BUFF], OFF); + set_pin(pgm->pinno[PIN_AVR_SCK], OFF); + /*use speed optimization with CAUTION*/ + usleep(20 * 1000); + + /* giving rst-pulse of at least 2 avr-clock-cycles, for + * security (2us @ 1MHz) */ + set_pin(pgm->pinno[PIN_AVR_RESET], ON); + usleep(20 * 1000); + + /*setting rst back to 0 */ + set_pin(pgm->pinno[PIN_AVR_RESET], OFF); + /*wait at least 20ms bevor issuing spi commands to avr */ + usleep(20 * 1000); + + return pgm->program_enable(pgm, p); +} + +static void avrftdi_disable(PROGRAMMER * pgm) +{ + return; +} + +static void avrftdi_enable(PROGRAMMER * pgm) +{ + return; +} + +static void avrftdi_display(PROGRAMMER * pgm, const char *p) +{ + return; +} + + +static int avrftdi_cmd(PROGRAMMER * pgm, unsigned char cmd[4], unsigned char res[4]) +{ + return avrftdi_transmit(TRX, cmd, res, sizeof(cmd)); +} + + +static int avrftdi_program_enable(PROGRAMMER * pgm, AVRPART * p) +{ + int i; + unsigned char buf[4]; + + memset(buf, 0, sizeof(buf)); + + if (p->op[AVR_OP_PGM_ENABLE] == NULL) { + fprintf(stderr, + "%s failure: Program Enable (PGM_ENABLE) command not defined for %s\n", + progname, p->desc); + return -1; + } + + avr_set_bits(p->op[AVR_OP_PGM_ENABLE], buf); + + for(i = 0; i < 4; i++) { + pgm->cmd(pgm, buf, buf); + if (buf[p->pollindex-1] != p->pollvalue) { + //try resetting + set_pin(pgm->pinno[PIN_AVR_RESET], ON); + usleep(20); + set_pin(pgm->pinno[PIN_AVR_RESET], OFF); + avr_set_bits(p->op[AVR_OP_PGM_ENABLE], buf); + } else + return 0; + } +#ifndef DRYRUN + return -1; +#else + return 0; +#endif +} + + +static int avrftdi_chip_erase(PROGRAMMER * pgm, AVRPART * p) +{ + unsigned char cmd[4]; + unsigned char res[4]; + + if (p->op[AVR_OP_CHIP_ERASE] == NULL) { + fprintf(stderr, + "%s failure Chip Erase (CHIP_ERASE) command not defined for %s\n", + progname, p->desc); + return -1; + } + + memset(cmd, 0, sizeof(cmd)); + + avr_set_bits(p->op[AVR_OP_CHIP_ERASE], cmd); + pgm->cmd(pgm, cmd, res); + usleep(p->chip_erase_delay); + pgm->initialize(pgm, p); + + return 0; +} + + +/* Load extended address byte command */ +static int avrftdi_lext(PROGRAMMER *pgm, AVRPART *p, AVRMEM *m, int address) +{ + unsigned char buf[] = {0x11, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00}; + + avr_set_bits(m->op[AVR_OP_LOAD_EXT_ADDR], &buf[3]); + avr_set_addr(m->op[AVR_OP_LOAD_EXT_ADDR], &buf[3], address); + + if(verbose > 1) + buf_dump(buf, sizeof(buf), + "load extended address command", 0, 16 * 3); + +#ifndef DRYRUN + E(ftdi_write_data(&ftdic, buf, sizeof(buf)) != sizeof(buf)); +#endif + return 0; +} + +static int avrftdi_eeprom_write(PROGRAMMER *pgm, AVRPART *p, AVRMEM *m, + int page_size, int len) +{ + unsigned char cmd[4]; + unsigned char *data = m->buf; + int add; + + avr_set_bits(m->op[AVR_OP_WRITE], cmd); + + for (add = 0; add < len; add++) + { + avr_set_addr(m->op[AVR_OP_WRITE], cmd, add); + avr_set_input(m->op[AVR_OP_WRITE], cmd, *data++); + + E(avrftdi_transmit(TX, cmd, cmd, 4) < 0); + + usleep((m->max_write_delay)); + if(verbose < 3) + report_progress(add, len, NULL); + } + return len; +} + +static int avrftdi_eeprom_read(PROGRAMMER *pgm, AVRPART *p, AVRMEM *m, + int page_size, int len) +{ + unsigned char cmd[4]; + unsigned char buffer[len], *bufptr = buffer; + + int add; + + memset(buffer, 0, sizeof(buffer)); + + for (add = 0; add < len; add++) + { + avr_set_bits(m->op[AVR_OP_READ], cmd); + avr_set_addr(m->op[AVR_OP_READ], cmd, add); + + E(avrftdi_transmit(TRX, cmd, cmd, 4) < 0); + + avr_get_output(m->op[AVR_OP_READ], cmd, bufptr++); + if(verbose < 3) + report_progress(add, len, NULL); + } + + memcpy(m->buf, buffer, len); + return len; +} + +static int avrftdi_flash_write(PROGRAMMER * pgm, AVRPART * p, AVRMEM * m, + int page_size, int len) +{ + int i; + int address = 0, buf_size; + int bytes = len; + int blocksize; + int use_lext_address = m->op[AVR_OP_LOAD_EXT_ADDR] != NULL; + unsigned char *buf, *bufptr; + unsigned char *buffer = m->buf; + unsigned char byte; + + + buf = (unsigned char*) malloc(4 * len + 4); + if (buf == NULL) { + fprintf(stderr, + "%s (avrftdi_flash_write): error allocating memory\n", + p->desc); + exit (-1); + } + + bufptr = buf; + + /* pre-check opcodes */ + if (m->op[AVR_OP_LOADPAGE_LO] == NULL) { + fprintf(stderr, + "%s failure: %s command not defined for %s\n", + progname, "AVR_OP_LOADPAGE_LO", p->desc); + return -1; + } + if (m->op[AVR_OP_LOADPAGE_HI] == NULL) { + fprintf(stderr, + "%s failure: %s command not defined for %s\n", + progname, "AVR_OP_LOADPAGE_HI", p->desc); + return -1; + } + + //page_size = (page_size > m->page_size) ? m->page_size : page_size - 8; + page_size = m->page_size; + + while (bytes) { + if (bytes > page_size) { + blocksize = (page_size)/2; + bytes -= (page_size); + } else { + blocksize = bytes/2; + bytes = 0; + } + + if(verbose > 2) + fprintf(stderr, + "-< bytes = %d of %d, blocksize = %d of %d\n", + len - bytes, len, blocksize, m->page_size / 2); + + /* if we do cross a 64k word boundary (or write the + * first page), we need to issue a 'load extended + * address byte' command, which is defined as 0x4d + * 0x00
0x00. As far as i know, this + * is only available on 256k parts. 64k word is 128k + * bytes. + */ + if (use_lext_address && !(bytes & 0x1ffff)) { + avrftdi_lext(pgm, p, m, address); + } + + for (i = 0; i < blocksize; i++) { + /*setting word*/ + avr_set_bits(m->op[AVR_OP_LOADPAGE_LO], bufptr); + avr_set_addr(m->op[AVR_OP_LOADPAGE_LO], bufptr, address); + avr_set_input(m->op[AVR_OP_LOADPAGE_LO], bufptr, *buffer++); + bufptr += 4; + avr_set_bits(m->op[AVR_OP_LOADPAGE_HI], bufptr); + avr_set_addr(m->op[AVR_OP_LOADPAGE_HI], bufptr, address); + avr_set_input(m->op[AVR_OP_LOADPAGE_HI], bufptr, *buffer++); + bufptr += 4; + address++; + } + + if (verbose > 2) + fprintf(stderr, + "address = %d, page_size = %d\n", + address, m->page_size); + + if (((address * 2) % m->page_size) == 0 || bytes == 0) { + if (m->op[AVR_OP_WRITEPAGE] == NULL) { + fprintf(stderr, + "%s failure: Write Page (WRITEPAGE) command not defined for %s\n", + progname, p->desc); + exit(1); + } else { + avr_set_bits(m->op[AVR_OP_WRITEPAGE], bufptr); + } + /* setting page address highbyte */ + avr_set_addr(m->op[AVR_OP_WRITEPAGE], + bufptr, address - 1); + bufptr += 4; + } + + buf_size = bufptr - buf; + + if(verbose > 3) + buf_dump(buf, buf_size, "command buffer", 0, 16*3); + if(verbose > 2) + fprintf(stderr, + "%s info: buffer size: %d\n", + progname, buf_size); + + E(avrftdi_transmit(TX, buf, buf, buf_size) < 0); + + bufptr = buf; + if (((address * 2) % m->page_size) == 0 || bytes == 0) { + do { + pgm->read_byte(pgm, p, m, + (address * 2) - 1, &byte); + } while (m->buf[(address*2) - 1] != byte); + } + + if (verbose < 3) + report_progress(2 * address, len, NULL); + } + return len; +} + +static int avrftdi_flash_read(PROGRAMMER * pgm, AVRPART * p, AVRMEM * m, + int page_size, int len) +{ + /* + *Reading from flash + */ + int use_lext_address = m->op[AVR_OP_LOAD_EXT_ADDR] != NULL; + int i, buf_index, buf_size = 0, psize = m->page_size; + unsigned char o_buf[4*len+4], *o_ptr = o_buf; + unsigned char i_buf[4*len+4]; + int address = 0; + int bytes = len; + int blocksize; + unsigned char buffer[m->size], *bufptr = buffer; + + memset(o_buf, 0, sizeof(o_buf)); + memset(i_buf, 0, sizeof(i_buf)); + memset(buffer, 0, sizeof(buffer)); + + /* pre-check opcodes */ + if (m->op[AVR_OP_READ_LO] == NULL) { + fprintf(stderr, + "%s failure: %s command not defined for %s\n", + progname, "AVR_OP_READ_LO", p->desc); + return -1; + } + if (m->op[AVR_OP_READ_HI] == NULL) { + fprintf(stderr, + "%s failure: %s command not defined for %s\n", + progname, "AVR_OP_READ_HI", p->desc); + return -1; + } + + while (bytes) { + if (bytes > psize) { + blocksize = psize/2; + bytes -= psize; + } else { + blocksize = bytes/2; + bytes = 0; + } + + if(use_lext_address && !(bytes & 0x1ffff)) { + avrftdi_lext(pgm, p, m, address); + } + + for(i = 0; i < blocksize; i++) { + if(verbose > 3) + fprintf(stderr, + "bufsize: %d, i: %d, add: %d\n", + buf_size, i, address); + avr_set_bits(m->op[AVR_OP_READ_LO], o_ptr); + avr_set_addr(m->op[AVR_OP_READ_LO], o_ptr, address); + o_ptr += 4; + avr_set_bits(m->op[AVR_OP_READ_HI], o_ptr); + avr_set_addr(m->op[AVR_OP_READ_HI], o_ptr, address); + o_ptr += 4; + + address++; + + //FIXME: why not program on per-page basis? + //maybe this covered a timing error in an earlier version? + buf_size = o_ptr - o_buf; + + if((buf_size >= (page_size - 8)) || ( i == blocksize-1)) { + E(avrftdi_transmit(TRX, o_buf, i_buf, buf_size) < 0); + + for(buf_index = 0; buf_index < buf_size; buf_index+=8) { + avr_get_output(m->op[AVR_OP_READ_LO], i_buf+buf_index, bufptr++); + avr_get_output(m->op[AVR_OP_READ_HI], i_buf+buf_index+4, bufptr++); + } + + if(verbose > 3) { + buf_dump(i_buf, buf_size, "i_buf", 0, 16); + } + o_ptr = o_buf; + } + } + if (verbose < 3) + report_progress(2 * address, len, NULL); + } + memcpy(m->buf, buffer, sizeof(buffer)); + + return len; +} + +static int avrftdi_paged_write(PROGRAMMER * pgm, AVRPART * p, AVRMEM * m, + int page_size, int n_bytes) +{ + if (strcmp(m->desc, "flash") == 0) + return avrftdi_flash_write(pgm, p, m, page_size, n_bytes); + else if (strcmp(m->desc, "eeprom") == 0) + return avrftdi_eeprom_write(pgm, p, m, page_size, n_bytes); + else + return -2; +} + +static int avrftdi_paged_load(PROGRAMMER * pgm, AVRPART * p, AVRMEM * m, + int page_size, int n_bytes) +{ + if (strcmp(m->desc, "flash") == 0) + return avrftdi_flash_read(pgm, p, m, page_size, n_bytes); + else if(strcmp(m->desc, "eeprom") == 0) + return avrftdi_eeprom_read(pgm, p, m, page_size, n_bytes); + else + return -2; +} + +void avrftdi_initpgm(PROGRAMMER * pgm) +{ + strcpy(pgm->type, "avrftdi"); + + pin_value=pin_direction=pin_inversion=led_mask=0; + /* + * mandatory functions + */ + + pgm->initialize = avrftdi_initialize; + pgm->display = avrftdi_display; + pgm->enable = avrftdi_enable; + pgm->disable = avrftdi_disable; + pgm->program_enable = avrftdi_program_enable; + pgm->chip_erase = avrftdi_chip_erase; + pgm->cmd = avrftdi_cmd; + pgm->open = avrftdi_open; + pgm->close = avrftdi_close; + pgm->read_byte = avr_read_byte_default; + pgm->write_byte = avr_write_byte_default; + + /* + * optional functions + */ + + pgm->paged_write = avrftdi_paged_write; + pgm->paged_load = avrftdi_paged_load; + + pgm->rdy_led = set_led_rdy; + pgm->err_led = set_led_err; + pgm->pgm_led = set_led_pgm; + pgm->vfy_led = set_led_vfy; + + +} + +#else /*HAVE_LIBFTDI*/ + +static int avrftdi_noftdi_open (struct programmer_t *pgm, char * name) +{ + fprintf(stderr, + "%s: error: no libftdi support. please compile again with libftdi installed.\n", + progname); + + exit(1); +} + +void avrftdi_initpgm(PROGRAMMER * pgm) +{ + strcpy(pgm->type, "avrftdi"); + pgm->open = avrftdi_noftdi_open; +} + +#endif /* HAVE_LIBFTDI */ + +#else /*HAVE_LIBUSB*/ + +static int avrftdi_nousb_open (struct programmer_t *pgm, char * name) +{ + fprintf(stderr, + "%s: error: no usb support. please compile again with libusb installed.\n", + progname); + + exit(1); +} + +void avrftdi_initpgm(PROGRAMMER * pgm) +{ + strcpy(pgm->type, "avrftdi"); + pgm->open = avrftdi_nousb_open; +} + +#endif /*HAVE_LIBUSB*/ + diff --git a/avrftdi.h b/avrftdi.h new file mode 100644 index 00000000..b1ffc893 --- /dev/null +++ b/avrftdi.h @@ -0,0 +1,56 @@ +/* + * avrftdi - extension for avrdude, Wolfgang Moser, Ville Voipio + * Copyright (C) 2011 Hannes Weisbach, Doug Springer + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* $Id$ */ + +#ifndef avrftdi_h +#define avrfdti_h + +#ifdef __cplusplus +extern "C" { +#endif + +#define SCK 0x01 +#define SDO 0x02 +#define SDI 0x04 + +#define RX 0x20 +#define TX 0x11 + +#define TRX (RX | TX) + +#define TYPE_C_D 0x500 +#define TYPE_H 0x700 +#define TYPE_4H 0x800 + +#define E(x) if ((x)) { fprintf(stdout, "%s:%d %s() %s: %s (%d)\n\t%s\n", __FILE__, __LINE__, __FUNCTION__, \ + #x, strerror(errno), errno, ftdi_get_error_string(&ftdic)); return -1; } + +#define E_VOID(x) if ((x)) { fprintf(stdout, "%s:%d %s() %s: %s (%d)\n\t%s\n", __FILE__, __LINE__, __FUNCTION__, \ + #x, strerror(errno), errno, ftdi_get_error_string(&ftdic)); } + +void avrftdi_initpgm (PROGRAMMER * pgm); + +#ifdef __cplusplus +} +#endif + +#endif + + diff --git a/config_gram.y b/config_gram.y index 2ff8452a..48ecf137 100644 --- a/config_gram.y +++ b/config_gram.y @@ -48,6 +48,7 @@ #include "avr.h" #include "jtagmkI.h" #include "jtagmkII.h" +#include "avrftdi.h" #if defined(WIN32NATIVE) #define strtok_r( _s, _sep, _lasts ) \ @@ -82,6 +83,7 @@ static int parse_cmdbits(OPCODE * op); %token K_PAGED %token K_ARDUINO +%token K_AVRFTDI %token K_BAUDRATE %token K_BS2 %token K_BUFF @@ -149,7 +151,13 @@ static int parse_cmdbits(OPCODE * op); %token K_STK600PP %token K_AVR910 %token K_USBASP +%token K_USBDEV +%token K_USBSN %token K_USBTINY +%token K_USBPID +%token K_USBPRODUCT +%token K_USBVENDOR +%token K_USBVID %token K_BUTTERFLY %token K_TYPE %token K_VCC @@ -432,6 +440,12 @@ prog_parm : } } | + K_TYPE TKN_EQUAL K_AVRFTDI { + { + avrftdi_initpgm(current_prog); + } + } | + K_TYPE TKN_EQUAL K_BUSPIRATE { { buspirate_initpgm(current_prog); @@ -590,7 +604,49 @@ prog_parm : } } } | + K_USBDEV TKN_EQUAL TKN_STRING { + { + strncpy(current_prog->usbdev, $3->value.string, PGM_USBSTRINGLEN); + current_prog->usbdev[PGM_USBSTRINGLEN-1] = 0; + free_token($3); + } + } | + K_USBVID TKN_EQUAL TKN_NUMBER { + { + current_prog->usbvid = $3->value.number; + } + } | + K_USBPID TKN_EQUAL TKN_NUMBER { + { + current_prog->usbpid = $3->value.number; + } + } | + + K_USBSN TKN_EQUAL TKN_STRING { + { + strncpy(current_prog->usbsn, $3->value.string, PGM_USBSTRINGLEN); + current_prog->usbsn[PGM_USBSTRINGLEN-1] = 0; + free_token($3); + } + } | + + K_USBVENDOR TKN_EQUAL TKN_STRING { + { + strncpy(current_prog->usbvendor, $3->value.string, PGM_USBSTRINGLEN); + current_prog->usbvendor[PGM_USBSTRINGLEN-1] = 0; + free_token($3); + } + } | + + K_USBPRODUCT TKN_EQUAL TKN_STRING { + { + strncpy(current_prog->usbproduct, $3->value.string, PGM_USBSTRINGLEN); + current_prog->usbproduct[PGM_USBSTRINGLEN-1] = 0; + free_token($3); + } + } | + K_BAUDRATE TKN_EQUAL TKN_NUMBER { { current_prog->baudrate = $3->value.number; diff --git a/configure.ac b/configure.ac index 895cca7c..36c880e2 100644 --- a/configure.ac +++ b/configure.ac @@ -83,7 +83,14 @@ if test x$have_libusb_1_0 = xyes; then AC_CHECK_HEADERS([libusb.h]) fi AC_SUBST(LIBUSB_1_0, $LIBUSB_1_0) - +AH_TEMPLATE([HAVE_LIBFTDI], + [Define if FTDI support is enabled via libftdi]) +AC_CHECK_LIB([ftdi], [ftdi_init], [have_libftdi=yes]) +if test x$have_libftdi = xyes; then + LIBFTDI="-lftdi" + AC_DEFINE([HAVE_LIBFTDI]) +fi +AC_SUBST(LIBFTDI, $LIBFTDI) # Checks for header files. AC_CHECK_HEADERS([limits.h stdlib.h string.h]) AC_CHECK_HEADERS([fcntl.h sys/ioctl.h sys/time.h termios.h unistd.h]) diff --git a/doc/avrdude.texi b/doc/avrdude.texi index 399e8ac4..0ea3150f 100644 --- a/doc/avrdude.texi +++ b/doc/avrdude.texi @@ -169,9 +169,14 @@ emulated on top of USB is likely to not work at all, or to work abysmally slow. The STK500, JTAG ICE, avr910, and avr109/butterfly use the serial port to communicate with the PC. -The STK600, JTAG ICE mkII, AVRISP mkII, USBasp, and USBtinyISP +The STK600, JTAG ICE mkII, AVRISP mkII, USBasp, avrftdi (and derivitives), and USBtinyISP programmers communicate through the USB, using @code{libusb} as a platform abstraction layer. +The avrftdi adds support for the FT2232C/D, FT2232H, and FT4232H devices. These all use +the MPSSE mode, which has a specific pin mapping. Bit 1 (the lsb of the byte in the config +file) is SCK. Bit 2 is MOSI, and Bit 3 is MISO. Bit 4 usually reset. The 2232C/D parts +are only supported on interface A, but the H parts can be either A or B (specified by the +usbdev config parameter). The STK500, STK600, JTAG ICE, and avr910 contain on-board logic to control the programming of the target device. The avr109 bootloader implements a protocol similar to avr910, but is diff --git a/lexer.l b/lexer.l index 926aca1c..d8790a68 100644 --- a/lexer.l +++ b/lexer.l @@ -120,6 +120,7 @@ allowfullpagebitstream { yylval=NULL; return K_ALLOWFULLPAGEBITSTREAM; } arduino { yylval=NULL; return K_ARDUINO; } avr910 { yylval=NULL; return K_AVR910; } avr910_devcode { yylval=NULL; return K_AVR910_DEVCODE; } +avrftdi { yylval=NULL; return K_AVRFTDI; } usbasp { yylval=NULL; return K_USBASP; } usbtiny { yylval=NULL; return K_USBTINY; } bank_size { yylval=NULL; return K_PAGE_SIZE; } @@ -197,6 +198,12 @@ stk600 { yylval=NULL; return K_STK600; } stk600hvsp { yylval=NULL; return K_STK600HVSP; } stk600pp { yylval=NULL; return K_STK600PP; } type { yylval=NULL; return K_TYPE; } +usbdev { yylval=NULL; return K_USBDEV; } +usbpid { yylval=NULL; return K_USBPID; } +usbproduct { yylval=NULL; return K_USBPRODUCT; } +usbsn { yylval=NULL; return K_USBSN; } +usbvendor { yylval=NULL; return K_USBVENDOR; } +usbvid { yylval=NULL; return K_USBVID; } vcc { yylval=NULL; return K_VCC; } vfyled { yylval=NULL; return K_VFYLED; } diff --git a/pgm.h b/pgm.h index 51c6dd4b..1542b247 100644 --- a/pgm.h +++ b/pgm.h @@ -36,6 +36,7 @@ #define PGM_DESCLEN 80 #define PGM_PORTLEN PATH_MAX #define PGM_TYPELEN 32 +#define PGM_USBSTRINGLEN 256 typedef enum { EXIT_VCC_UNSPEC, @@ -60,6 +61,9 @@ typedef struct programmer_t { int ppidata; int ppictrl; int baudrate; + int usbvid, usbpid; + char usbdev[PGM_USBSTRINGLEN], usbsn[PGM_USBSTRINGLEN]; + char usbvendor[PGM_USBSTRINGLEN], usbproduct[PGM_USBSTRINGLEN]; double bitclock; /* JTAG ICE clock period in microseconds */ int ispdelay; /* ISP clock delay */ union filedescriptor fd;