mirror of
https://github.com/mariusgreuel/avrdude.git
synced 2026-02-05 01:40:07 +00:00
Merged AVRDUDES/main into SerialUPDI branch
This commit is contained in:
217
src/Makefile.am
Normal file
217
src/Makefile.am
Normal file
@@ -0,0 +1,217 @@
|
||||
#
|
||||
# avrdude - A Downloader/Uploader for AVR device programmers
|
||||
# Copyright (C) 2003, 2004 Theodore A. Roth <troth@openavr.org>
|
||||
#
|
||||
# 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, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
|
||||
# In order to get verbose build messages rather than a summary line
|
||||
# only, either use
|
||||
#
|
||||
# ./configure --disable-silent-rules
|
||||
#
|
||||
# or run make like
|
||||
#
|
||||
# make V=1
|
||||
|
||||
#
|
||||
# $Id$
|
||||
#
|
||||
|
||||
EXTRA_DIST = \
|
||||
avrdude.1 \
|
||||
avrdude.spec \
|
||||
bootstrap
|
||||
|
||||
CLEANFILES = \
|
||||
config_gram.c \
|
||||
config_gram.h \
|
||||
lexer.c
|
||||
|
||||
BUILT_SOURCES = $(CLEANFILES)
|
||||
|
||||
#SUBDIRS = doc
|
||||
#DIST_SUBDIRS = doc
|
||||
|
||||
# . lets build this directory before the following in SUBDIRS
|
||||
SUBDIRS = .
|
||||
# doc comes here, and we want to use the built avrdude to generate the parts list
|
||||
SUBDIRS += @SUBDIRS_AC@
|
||||
DIST_SUBDIRS = @DIST_SUBDIRS_AC@
|
||||
|
||||
AM_YFLAGS = -d
|
||||
|
||||
avrdude_CPPFLAGS = -DCONFIG_DIR=\"$(sysconfdir)\"
|
||||
|
||||
libavrdude_a_CPPFLAGS = -DCONFIG_DIR=\"$(sysconfdir)\"
|
||||
libavrdude_la_CPPFLAGS = $(libavrdude_a_CPPFLAGS)
|
||||
|
||||
avrdude_CFLAGS = @ENABLE_WARNINGS@
|
||||
|
||||
libavrdude_a_CFLAGS = @ENABLE_WARNINGS@
|
||||
libavrdude_la_CFLAGS = $(libavrdude_a_CFLAGS)
|
||||
|
||||
avrdude_LDADD = $(top_builddir)/$(noinst_LIBRARIES) @LIBUSB_1_0@ @LIBHIDAPI@ @LIBUSB@ @LIBFTDI1@ @LIBFTDI@ @LIBHID@ @LIBELF@ @LIBPTHREAD@ -lm
|
||||
|
||||
bin_PROGRAMS = avrdude
|
||||
|
||||
noinst_LIBRARIES = libavrdude.a
|
||||
lib_LTLIBRARIES = libavrdude.la
|
||||
|
||||
# automake thinks these generated files should be in the distribution,
|
||||
# but this might cause trouble for some users, so we rather don't want
|
||||
# to have them there.
|
||||
#
|
||||
# See
|
||||
#
|
||||
# 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
|
||||
|
||||
libavrdude_a_SOURCES = \
|
||||
config_gram.y \
|
||||
lexer.l \
|
||||
arduino.h \
|
||||
arduino.c \
|
||||
avr.c \
|
||||
avr910.c \
|
||||
avr910.h \
|
||||
avrdude.h \
|
||||
avrftdi.c \
|
||||
avrftdi.h \
|
||||
avrftdi_private.h \
|
||||
avrftdi_tpi.c \
|
||||
avrftdi_tpi.h \
|
||||
avrpart.c \
|
||||
bitbang.c \
|
||||
bitbang.h \
|
||||
buspirate.c \
|
||||
buspirate.h \
|
||||
butterfly.c \
|
||||
butterfly.h \
|
||||
config.c \
|
||||
config.h \
|
||||
confwin.c \
|
||||
crc16.c \
|
||||
crc16.h \
|
||||
dfu.c \
|
||||
dfu.h \
|
||||
fileio.c \
|
||||
flip1.c \
|
||||
flip1.h \
|
||||
flip2.c \
|
||||
flip2.h \
|
||||
freebsd_ppi.h \
|
||||
ft245r.c \
|
||||
ft245r.h \
|
||||
jtagmkI.c \
|
||||
jtagmkI.h \
|
||||
jtagmkI_private.h \
|
||||
jtagmkII.c \
|
||||
jtagmkII.h \
|
||||
jtagmkII_private.h \
|
||||
jtag3.c \
|
||||
jtag3.h \
|
||||
jtag3_private.h \
|
||||
libavrdude.h \
|
||||
linuxgpio.c \
|
||||
linuxgpio.h \
|
||||
linuxspi.c \
|
||||
linuxspi.h \
|
||||
linux_ppdev.h \
|
||||
lists.c \
|
||||
my_ddk_hidsdi.h \
|
||||
par.c \
|
||||
par.h \
|
||||
pgm.c \
|
||||
pgm_type.c \
|
||||
pickit2.c \
|
||||
pickit2.h \
|
||||
pindefs.c \
|
||||
ppi.c \
|
||||
ppi.h \
|
||||
ppiwin.c \
|
||||
safemode.c \
|
||||
serbb.h \
|
||||
serbb_posix.c \
|
||||
serbb_win32.c \
|
||||
ser_avrdoper.c \
|
||||
ser_posix.c \
|
||||
ser_win32.c \
|
||||
solaris_ecpp.h \
|
||||
stk500.c \
|
||||
stk500.h \
|
||||
stk500_private.h \
|
||||
stk500v2.c \
|
||||
stk500v2.h \
|
||||
stk500v2_private.h \
|
||||
stk500generic.c \
|
||||
stk500generic.h \
|
||||
tpi.h \
|
||||
usbasp.c \
|
||||
usbasp.h \
|
||||
serialupdi.c \
|
||||
serialupdi.h \
|
||||
updi_constants.h \
|
||||
updi_link.c \
|
||||
updi_link.h \
|
||||
updi_state.c \
|
||||
updi_state.h \
|
||||
updi_readwrite.c \
|
||||
updi_readwrite.h \
|
||||
updi_nvm.c \
|
||||
updi_nvm.h \
|
||||
usbdevs.h \
|
||||
usb_hidapi.c \
|
||||
usb_libusb.c \
|
||||
usbtiny.h \
|
||||
usbtiny.c \
|
||||
update.c \
|
||||
wiring.h \
|
||||
wiring.c \
|
||||
xbee.h \
|
||||
xbee.c
|
||||
libavrdude_la_SOURCES = $(libavrdude_a_SOURCES)
|
||||
libavrdude_la_LDFLAGS = -version-info 1:0
|
||||
|
||||
include_HEADERS = libavrdude.h
|
||||
|
||||
avrdude_SOURCES = \
|
||||
main.c \
|
||||
term.c \
|
||||
term.h
|
||||
|
||||
man_MANS = avrdude.1
|
||||
|
||||
sysconf_DATA = avrdude.conf
|
||||
|
||||
install-exec-local: backup-avrdude-conf
|
||||
|
||||
distclean-local:
|
||||
rm -f avrdude.conf
|
||||
|
||||
# This will get run before the config file is installed.
|
||||
backup-avrdude-conf:
|
||||
@echo "Backing up avrdude.conf in ${DESTDIR}${sysconfdir}"
|
||||
@if test -e ${DESTDIR}${sysconfdir}/avrdude.conf; then \
|
||||
cp -pR ${DESTDIR}${sysconfdir}/avrdude.conf \
|
||||
${DESTDIR}${sysconfdir}/avrdude.conf.bak; \
|
||||
fi
|
||||
|
||||
ACLOCAL_AMFLAGS = -I m4
|
||||
133
src/arduino.c
Normal file
133
src/arduino.c
Normal file
@@ -0,0 +1,133 @@
|
||||
/*
|
||||
* avrdude - A Downloader/Uploader for AVR device programmers
|
||||
* Copyright (C) 2009 Lars Immisch
|
||||
*
|
||||
* 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/* $Id$ */
|
||||
|
||||
/*
|
||||
* avrdude interface for Arduino programmer
|
||||
*
|
||||
* The Arduino programmer is mostly a STK500v1, just the signature bytes
|
||||
* are read differently.
|
||||
*/
|
||||
|
||||
#include "ac_cfg.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "avrdude.h"
|
||||
#include "libavrdude.h"
|
||||
#include "stk500_private.h"
|
||||
#include "stk500.h"
|
||||
#include "arduino.h"
|
||||
|
||||
/* read signature bytes - arduino version */
|
||||
static int arduino_read_sig_bytes(PROGRAMMER * pgm, AVRPART * p, AVRMEM * m)
|
||||
{
|
||||
unsigned char buf[32];
|
||||
|
||||
/* Signature byte reads are always 3 bytes. */
|
||||
|
||||
if (m->size < 3) {
|
||||
avrdude_message(MSG_INFO, "%s: memsize too small for sig byte read", progname);
|
||||
return -1;
|
||||
}
|
||||
|
||||
buf[0] = Cmnd_STK_READ_SIGN;
|
||||
buf[1] = Sync_CRC_EOP;
|
||||
|
||||
serial_send(&pgm->fd, buf, 2);
|
||||
|
||||
if (serial_recv(&pgm->fd, buf, 5) < 0)
|
||||
return -1;
|
||||
if (buf[0] == Resp_STK_NOSYNC) {
|
||||
avrdude_message(MSG_INFO, "%s: stk500_cmd(): programmer is out of sync\n",
|
||||
progname);
|
||||
return -1;
|
||||
} else if (buf[0] != Resp_STK_INSYNC) {
|
||||
avrdude_message(MSG_INFO, "\n%s: arduino_read_sig_bytes(): (a) protocol error, "
|
||||
"expect=0x%02x, resp=0x%02x\n",
|
||||
progname, Resp_STK_INSYNC, buf[0]);
|
||||
return -2;
|
||||
}
|
||||
if (buf[4] != Resp_STK_OK) {
|
||||
avrdude_message(MSG_INFO, "\n%s: arduino_read_sig_bytes(): (a) protocol error, "
|
||||
"expect=0x%02x, resp=0x%02x\n",
|
||||
progname, Resp_STK_OK, buf[4]);
|
||||
return -3;
|
||||
}
|
||||
|
||||
m->buf[0] = buf[1];
|
||||
m->buf[1] = buf[2];
|
||||
m->buf[2] = buf[3];
|
||||
|
||||
return 3;
|
||||
}
|
||||
|
||||
static int arduino_open(PROGRAMMER * pgm, char * port)
|
||||
{
|
||||
union pinfo pinfo;
|
||||
strcpy(pgm->port, port);
|
||||
pinfo.serialinfo.baud = pgm->baudrate? pgm->baudrate: 115200;
|
||||
pinfo.serialinfo.cflags = SERIAL_8N1;
|
||||
if (serial_open(port, pinfo, &pgm->fd)==-1) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Clear DTR and RTS to unload the RESET capacitor
|
||||
* (for example in Arduino) */
|
||||
serial_set_dtr_rts(&pgm->fd, 0);
|
||||
usleep(250*1000);
|
||||
/* Set DTR and RTS back to high */
|
||||
serial_set_dtr_rts(&pgm->fd, 1);
|
||||
usleep(50*1000);
|
||||
|
||||
/*
|
||||
* drain any extraneous input
|
||||
*/
|
||||
stk500_drain(pgm, 0);
|
||||
|
||||
if (stk500_getsync(pgm) < 0)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void arduino_close(PROGRAMMER * pgm)
|
||||
{
|
||||
serial_set_dtr_rts(&pgm->fd, 0);
|
||||
serial_close(&pgm->fd);
|
||||
pgm->fd.ifd = -1;
|
||||
}
|
||||
|
||||
const char arduino_desc[] = "Arduino programmer";
|
||||
|
||||
void arduino_initpgm(PROGRAMMER * pgm)
|
||||
{
|
||||
/* This is mostly a STK500; just the signature is read
|
||||
differently than on real STK500v1
|
||||
and the DTR signal is set when opening the serial port
|
||||
for the Auto-Reset feature */
|
||||
stk500_initpgm(pgm);
|
||||
|
||||
strcpy(pgm->type, "Arduino");
|
||||
pgm->read_sig_bytes = arduino_read_sig_bytes;
|
||||
pgm->open = arduino_open;
|
||||
pgm->close = arduino_close;
|
||||
}
|
||||
29
src/arduino.h
Normal file
29
src/arduino.h
Normal file
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
* avrdude - A Downloader/Uploader for AVR device programmers
|
||||
* Copyright (C) 2009 Lars Immisch
|
||||
*
|
||||
* 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/* $Id$ */
|
||||
|
||||
#ifndef arduino_h__
|
||||
#define arduino_h__
|
||||
|
||||
extern const char arduino_desc[];
|
||||
void arduino_initpgm (PROGRAMMER * pgm);
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
775
src/avr910.c
Normal file
775
src/avr910.c
Normal file
@@ -0,0 +1,775 @@
|
||||
/*
|
||||
* avrdude - A Downloader/Uploader for AVR device programmers
|
||||
* Copyright (C) 2003-2004 Theodore A. Roth <troth@openavr.org>
|
||||
* Copyright 2007 Joerg Wunsch <j@uriah.heep.sax.de>
|
||||
* Copyright 2008 Klaus Leidinger <klaus@mikrocontroller-projekte.de>
|
||||
*
|
||||
* 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/* $Id$ */
|
||||
|
||||
/*
|
||||
* avrdude interface for Atmel Low Cost Serial programmers which adher to the
|
||||
* protocol described in application note avr910.
|
||||
*/
|
||||
|
||||
#include "ac_cfg.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <ctype.h>
|
||||
#include <sys/time.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "avrdude.h"
|
||||
#include "libavrdude.h"
|
||||
|
||||
#include "avr910.h"
|
||||
|
||||
/*
|
||||
* Private data for this programmer.
|
||||
*/
|
||||
struct pdata
|
||||
{
|
||||
char has_auto_incr_addr;
|
||||
unsigned char devcode;
|
||||
unsigned int buffersize;
|
||||
unsigned char test_blockmode;
|
||||
unsigned char use_blockmode;
|
||||
};
|
||||
|
||||
#define PDATA(pgm) ((struct pdata *)(pgm->cookie))
|
||||
|
||||
static void avr910_setup(PROGRAMMER * pgm)
|
||||
{
|
||||
if ((pgm->cookie = malloc(sizeof(struct pdata))) == 0) {
|
||||
avrdude_message(MSG_INFO, "%s: avr910_setup(): Out of memory allocating private data\n",
|
||||
progname);
|
||||
exit(1);
|
||||
}
|
||||
memset(pgm->cookie, 0, sizeof(struct pdata));
|
||||
PDATA(pgm)->test_blockmode = 1;
|
||||
}
|
||||
|
||||
static void avr910_teardown(PROGRAMMER * pgm)
|
||||
{
|
||||
free(pgm->cookie);
|
||||
}
|
||||
|
||||
|
||||
static int avr910_send(PROGRAMMER * pgm, char * buf, size_t len)
|
||||
{
|
||||
return serial_send(&pgm->fd, (unsigned char *)buf, len);
|
||||
}
|
||||
|
||||
|
||||
static int avr910_recv(PROGRAMMER * pgm, char * buf, size_t len)
|
||||
{
|
||||
int rv;
|
||||
|
||||
rv = serial_recv(&pgm->fd, (unsigned char *)buf, len);
|
||||
if (rv < 0) {
|
||||
avrdude_message(MSG_INFO, "%s: avr910_recv(): programmer is not responding\n",
|
||||
progname);
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int avr910_drain(PROGRAMMER * pgm, int display)
|
||||
{
|
||||
return serial_drain(&pgm->fd, display);
|
||||
}
|
||||
|
||||
|
||||
static int avr910_vfy_cmd_sent(PROGRAMMER * pgm, char * errmsg)
|
||||
{
|
||||
char c;
|
||||
|
||||
avr910_recv(pgm, &c, 1);
|
||||
if (c != '\r') {
|
||||
avrdude_message(MSG_INFO, "%s: error: programmer did not respond to command: %s\n",
|
||||
progname, errmsg);
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* issue the 'chip erase' command to the AVR device
|
||||
*/
|
||||
static int avr910_chip_erase(PROGRAMMER * pgm, AVRPART * p)
|
||||
{
|
||||
avr910_send(pgm, "e", 1);
|
||||
if (avr910_vfy_cmd_sent(pgm, "chip erase") < 0)
|
||||
return -1;
|
||||
|
||||
/*
|
||||
* avr910 firmware may not delay long enough
|
||||
*/
|
||||
usleep (p->chip_erase_delay);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int avr910_enter_prog_mode(PROGRAMMER * pgm)
|
||||
{
|
||||
avr910_send(pgm, "P", 1);
|
||||
return avr910_vfy_cmd_sent(pgm, "enter prog mode");
|
||||
}
|
||||
|
||||
|
||||
static int avr910_leave_prog_mode(PROGRAMMER * pgm)
|
||||
{
|
||||
avr910_send(pgm, "L", 1);
|
||||
return avr910_vfy_cmd_sent(pgm, "leave prog mode");
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* issue the 'program enable' command to the AVR device
|
||||
*/
|
||||
static int avr910_program_enable(PROGRAMMER * pgm, AVRPART * p)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* initialize the AVR device and prepare it to accept commands
|
||||
*/
|
||||
static int avr910_initialize(PROGRAMMER * pgm, AVRPART * p)
|
||||
{
|
||||
char id[8];
|
||||
char sw[2];
|
||||
char hw[2];
|
||||
char buf[10];
|
||||
char type;
|
||||
char c;
|
||||
AVRPART * part;
|
||||
|
||||
/* Get the programmer identifier. Programmer returns exactly 7 chars
|
||||
_without_ the null.*/
|
||||
|
||||
avr910_send(pgm, "S", 1);
|
||||
memset (id, 0, sizeof(id));
|
||||
avr910_recv(pgm, id, sizeof(id)-1);
|
||||
|
||||
/* Get the HW and SW versions to see if the programmer is present. */
|
||||
|
||||
avr910_send(pgm, "V", 1);
|
||||
avr910_recv(pgm, sw, sizeof(sw));
|
||||
|
||||
avr910_send(pgm, "v", 1);
|
||||
avr910_recv(pgm, hw, sizeof(hw));
|
||||
|
||||
/* Get the programmer type (serial or parallel). Expect serial. */
|
||||
|
||||
avr910_send(pgm, "p", 1);
|
||||
avr910_recv(pgm, &type, 1);
|
||||
|
||||
avrdude_message(MSG_INFO, "Found programmer: Id = \"%s\"; type = %c\n", id, type);
|
||||
avrdude_message(MSG_INFO, " Software Version = %c.%c; ", sw[0], sw[1]);
|
||||
avrdude_message(MSG_INFO, "Hardware Version = %c.%c\n", hw[0], hw[1]);
|
||||
|
||||
/* See if programmer supports autoincrement of address. */
|
||||
|
||||
avr910_send(pgm, "a", 1);
|
||||
avr910_recv(pgm, &PDATA(pgm)->has_auto_incr_addr, 1);
|
||||
if (PDATA(pgm)->has_auto_incr_addr == 'Y')
|
||||
avrdude_message(MSG_INFO, "Programmer supports auto addr increment.\n");
|
||||
|
||||
/* Check support for buffered memory access, ignore if not available */
|
||||
|
||||
if (PDATA(pgm)->test_blockmode == 1) {
|
||||
avr910_send(pgm, "b", 1);
|
||||
avr910_recv(pgm, &c, 1);
|
||||
if (c == 'Y') {
|
||||
avr910_recv(pgm, &c, 1);
|
||||
PDATA(pgm)->buffersize = (unsigned int)(unsigned char)c<<8;
|
||||
avr910_recv(pgm, &c, 1);
|
||||
PDATA(pgm)->buffersize += (unsigned int)(unsigned char)c;
|
||||
avrdude_message(MSG_INFO, "Programmer supports buffered memory access with "
|
||||
"buffersize = %u bytes.\n",
|
||||
PDATA(pgm)->buffersize);
|
||||
PDATA(pgm)->use_blockmode = 1;
|
||||
} else {
|
||||
PDATA(pgm)->use_blockmode = 0;
|
||||
}
|
||||
} else {
|
||||
PDATA(pgm)->use_blockmode = 0;
|
||||
}
|
||||
|
||||
if (PDATA(pgm)->devcode == 0) {
|
||||
char devtype_1st;
|
||||
int dev_supported = 0;
|
||||
|
||||
/* Get list of devices that the programmer supports. */
|
||||
|
||||
avr910_send(pgm, "t", 1);
|
||||
avrdude_message(MSG_INFO, "\nProgrammer supports the following devices:\n");
|
||||
devtype_1st = 0;
|
||||
while (1) {
|
||||
avr910_recv(pgm, &c, 1);
|
||||
if (devtype_1st == 0)
|
||||
devtype_1st = c;
|
||||
if (c == 0)
|
||||
break;
|
||||
part = locate_part_by_avr910_devcode(part_list, c);
|
||||
|
||||
avrdude_message(MSG_INFO, " Device code: 0x%02x = %s\n", c, part ? part->desc : "(unknown)");
|
||||
|
||||
/* FIXME: Need to lookup devcode and report the device. */
|
||||
|
||||
if (p->avr910_devcode == c)
|
||||
dev_supported = 1;
|
||||
};
|
||||
avrdude_message(MSG_INFO, "\n");
|
||||
|
||||
if (!dev_supported) {
|
||||
avrdude_message(MSG_INFO, "%s: %s: selected device is not supported by programmer: %s\n",
|
||||
progname, ovsigck? "warning": "error", p->id);
|
||||
if (!ovsigck)
|
||||
return -1;
|
||||
}
|
||||
/* If the user forced the selection, use the first device
|
||||
type that is supported by the programmer. */
|
||||
buf[1] = ovsigck? devtype_1st: p->avr910_devcode;
|
||||
} else {
|
||||
/* devcode overridden by -x devcode= option */
|
||||
buf[1] = (char)(PDATA(pgm)->devcode);
|
||||
}
|
||||
|
||||
/* Tell the programmer which part we selected. */
|
||||
buf[0] = 'T';
|
||||
/* buf[1] has been set up above */
|
||||
|
||||
avr910_send(pgm, buf, 2);
|
||||
avr910_vfy_cmd_sent(pgm, "select device");
|
||||
|
||||
avrdude_message(MSG_NOTICE, "%s: avr910_devcode selected: 0x%02x\n",
|
||||
progname, (unsigned)buf[1]);
|
||||
|
||||
avr910_enter_prog_mode(pgm);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static void avr910_disable(PROGRAMMER * pgm)
|
||||
{
|
||||
/* Do nothing. */
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
static void avr910_enable(PROGRAMMER * pgm)
|
||||
{
|
||||
/* Do nothing. */
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* transmit an AVR device command and return the results; 'cmd' and
|
||||
* 'res' must point to at least a 4 byte data buffer
|
||||
*/
|
||||
static int avr910_cmd(PROGRAMMER * pgm, const unsigned char *cmd,
|
||||
unsigned char *res)
|
||||
{
|
||||
char buf[5];
|
||||
|
||||
/* FIXME: Insert version check here */
|
||||
|
||||
buf[0] = '.'; /* New Universal Command */
|
||||
buf[1] = cmd[0];
|
||||
buf[2] = cmd[1];
|
||||
buf[3] = cmd[2];
|
||||
buf[4] = cmd[3];
|
||||
|
||||
avr910_send (pgm, buf, 5);
|
||||
avr910_recv (pgm, buf, 2);
|
||||
|
||||
res[0] = 0x00; /* Dummy value */
|
||||
res[1] = cmd[0];
|
||||
res[2] = cmd[1];
|
||||
res[3] = buf[0];
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int avr910_parseextparms(PROGRAMMER * pgm, LISTID extparms)
|
||||
{
|
||||
LNODEID ln;
|
||||
const char *extended_param;
|
||||
int rv = 0;
|
||||
|
||||
for (ln = lfirst(extparms); ln; ln = lnext(ln)) {
|
||||
extended_param = ldata(ln);
|
||||
|
||||
if (strncmp(extended_param, "devcode=", strlen("devcode=")) == 0) {
|
||||
int devcode;
|
||||
if (sscanf(extended_param, "devcode=%i", &devcode) != 1 ||
|
||||
devcode <= 0 || devcode > 255) {
|
||||
avrdude_message(MSG_INFO, "%s: avr910_parseextparms(): invalid devcode '%s'\n",
|
||||
progname, extended_param);
|
||||
rv = -1;
|
||||
continue;
|
||||
}
|
||||
avrdude_message(MSG_NOTICE2, "%s: avr910_parseextparms(): devcode overwritten as 0x%02x\n",
|
||||
progname, devcode);
|
||||
PDATA(pgm)->devcode = devcode;
|
||||
|
||||
continue;
|
||||
}
|
||||
if (strncmp(extended_param, "no_blockmode", strlen("no_blockmode")) == 0) {
|
||||
avrdude_message(MSG_NOTICE2, "%s: avr910_parseextparms(-x): no testing for Blockmode\n",
|
||||
progname);
|
||||
PDATA(pgm)->test_blockmode = 0;
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
avrdude_message(MSG_INFO, "%s: avr910_parseextparms(): invalid extended parameter '%s'\n",
|
||||
progname, extended_param);
|
||||
rv = -1;
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
|
||||
static int avr910_open(PROGRAMMER * pgm, char * port)
|
||||
{
|
||||
union pinfo pinfo;
|
||||
/*
|
||||
* If baudrate was not specified use 19.200 Baud
|
||||
*/
|
||||
if(pgm->baudrate == 0) {
|
||||
pgm->baudrate = 19200;
|
||||
}
|
||||
|
||||
strcpy(pgm->port, port);
|
||||
pinfo.serialinfo.baud = pgm->baudrate;
|
||||
pinfo.serialinfo.cflags = SERIAL_8N1;
|
||||
if (serial_open(port, pinfo, &pgm->fd)==-1) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* drain any extraneous input
|
||||
*/
|
||||
avr910_drain (pgm, 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void avr910_close(PROGRAMMER * pgm)
|
||||
{
|
||||
avr910_leave_prog_mode(pgm);
|
||||
|
||||
serial_close(&pgm->fd);
|
||||
pgm->fd.ifd = -1;
|
||||
}
|
||||
|
||||
|
||||
static void avr910_display(PROGRAMMER * pgm, const char * p)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
static void avr910_set_addr(PROGRAMMER * pgm, unsigned long addr)
|
||||
{
|
||||
char cmd[3];
|
||||
|
||||
cmd[0] = 'A';
|
||||
cmd[1] = (addr >> 8) & 0xff;
|
||||
cmd[2] = addr & 0xff;
|
||||
|
||||
avr910_send(pgm, cmd, sizeof(cmd));
|
||||
avr910_vfy_cmd_sent(pgm, "set addr");
|
||||
}
|
||||
|
||||
|
||||
static int avr910_write_byte(PROGRAMMER * pgm, AVRPART * p, AVRMEM * m,
|
||||
unsigned long addr, unsigned char value)
|
||||
{
|
||||
char cmd[2];
|
||||
|
||||
if (strcmp(m->desc, "flash") == 0) {
|
||||
if (addr & 0x01) {
|
||||
cmd[0] = 'C'; /* Write Program Mem high byte */
|
||||
}
|
||||
else {
|
||||
cmd[0] = 'c';
|
||||
}
|
||||
|
||||
addr >>= 1;
|
||||
}
|
||||
else if (strcmp(m->desc, "eeprom") == 0) {
|
||||
cmd[0] = 'D';
|
||||
}
|
||||
else {
|
||||
return avr_write_byte_default(pgm, p, m, addr, value);
|
||||
}
|
||||
|
||||
cmd[1] = value;
|
||||
|
||||
avr910_set_addr(pgm, addr);
|
||||
|
||||
avr910_send(pgm, cmd, sizeof(cmd));
|
||||
avr910_vfy_cmd_sent(pgm, "write byte");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int avr910_read_byte_flash(PROGRAMMER * pgm, AVRPART * p, AVRMEM * m,
|
||||
unsigned long addr, unsigned char * value)
|
||||
{
|
||||
char buf[2];
|
||||
|
||||
avr910_set_addr(pgm, addr >> 1);
|
||||
|
||||
avr910_send(pgm, "R", 1);
|
||||
|
||||
/* Read back the program mem word (MSB first) */
|
||||
avr910_recv(pgm, buf, sizeof(buf));
|
||||
|
||||
if ((addr & 0x01) == 0) {
|
||||
*value = buf[1];
|
||||
}
|
||||
else {
|
||||
*value = buf[0];
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int avr910_read_byte_eeprom(PROGRAMMER * pgm, AVRPART * p, AVRMEM * m,
|
||||
unsigned long addr, unsigned char * value)
|
||||
{
|
||||
avr910_set_addr(pgm, addr);
|
||||
avr910_send(pgm, "d", 1);
|
||||
avr910_recv(pgm, (char *)value, 1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int avr910_read_byte(PROGRAMMER * pgm, AVRPART * p, AVRMEM * m,
|
||||
unsigned long addr, unsigned char * value)
|
||||
{
|
||||
if (strcmp(m->desc, "flash") == 0) {
|
||||
return avr910_read_byte_flash(pgm, p, m, addr, value);
|
||||
}
|
||||
|
||||
if (strcmp(m->desc, "eeprom") == 0) {
|
||||
return avr910_read_byte_eeprom(pgm, p, m, addr, value);
|
||||
}
|
||||
|
||||
return avr_read_byte_default(pgm, p, m, addr, value);
|
||||
}
|
||||
|
||||
|
||||
static int avr910_paged_write_flash(PROGRAMMER * pgm, AVRPART * p, AVRMEM * m,
|
||||
unsigned int page_size,
|
||||
unsigned int addr, unsigned int n_bytes)
|
||||
{
|
||||
unsigned char cmd[] = {'c', 'C'};
|
||||
char buf[2];
|
||||
unsigned int max_addr = addr + n_bytes;
|
||||
unsigned int page_addr;
|
||||
int page_bytes = page_size;
|
||||
int page_wr_cmd_pending = 0;
|
||||
|
||||
page_addr = addr;
|
||||
avr910_set_addr(pgm, addr>>1);
|
||||
|
||||
while (addr < max_addr) {
|
||||
page_wr_cmd_pending = 1;
|
||||
buf[0] = cmd[addr & 0x01];
|
||||
buf[1] = m->buf[addr];
|
||||
avr910_send(pgm, buf, sizeof(buf));
|
||||
avr910_vfy_cmd_sent(pgm, "write byte");
|
||||
|
||||
addr++;
|
||||
page_bytes--;
|
||||
|
||||
if (m->paged && (page_bytes == 0)) {
|
||||
/* Send the "Issue Page Write" if we have sent a whole page. */
|
||||
|
||||
avr910_set_addr(pgm, page_addr>>1);
|
||||
avr910_send(pgm, "m", 1);
|
||||
avr910_vfy_cmd_sent(pgm, "flush page");
|
||||
|
||||
page_wr_cmd_pending = 0;
|
||||
usleep(m->max_write_delay);
|
||||
avr910_set_addr(pgm, addr>>1);
|
||||
|
||||
/* Set page address for next page. */
|
||||
|
||||
page_addr = addr;
|
||||
page_bytes = page_size;
|
||||
}
|
||||
else if ((PDATA(pgm)->has_auto_incr_addr != 'Y') && ((addr & 0x01) == 0)) {
|
||||
avr910_set_addr(pgm, addr>>1);
|
||||
}
|
||||
}
|
||||
|
||||
/* If we didn't send the page wr cmd after the last byte written in the
|
||||
loop, send it now. */
|
||||
|
||||
if (page_wr_cmd_pending) {
|
||||
avr910_set_addr(pgm, page_addr>>1);
|
||||
avr910_send(pgm, "m", 1);
|
||||
avr910_vfy_cmd_sent(pgm, "flush final page");
|
||||
usleep(m->max_write_delay);
|
||||
}
|
||||
|
||||
return addr;
|
||||
}
|
||||
|
||||
|
||||
static int avr910_paged_write_eeprom(PROGRAMMER * pgm, AVRPART * p,
|
||||
AVRMEM * m,
|
||||
unsigned int page_size,
|
||||
unsigned int addr, unsigned int n_bytes)
|
||||
{
|
||||
char cmd[2];
|
||||
unsigned int max_addr = addr + n_bytes;
|
||||
|
||||
avr910_set_addr(pgm, addr);
|
||||
|
||||
cmd[0] = 'D';
|
||||
|
||||
while (addr < max_addr) {
|
||||
cmd[1] = m->buf[addr];
|
||||
avr910_send(pgm, cmd, sizeof(cmd));
|
||||
avr910_vfy_cmd_sent(pgm, "write byte");
|
||||
usleep(m->max_write_delay);
|
||||
|
||||
addr++;
|
||||
|
||||
if (PDATA(pgm)->has_auto_incr_addr != 'Y') {
|
||||
avr910_set_addr(pgm, addr);
|
||||
}
|
||||
}
|
||||
|
||||
return addr;
|
||||
}
|
||||
|
||||
|
||||
static int avr910_paged_write(PROGRAMMER * pgm, AVRPART * p, AVRMEM * m,
|
||||
unsigned int page_size,
|
||||
unsigned int addr, unsigned int n_bytes)
|
||||
{
|
||||
int rval = 0;
|
||||
if (PDATA(pgm)->use_blockmode == 0) {
|
||||
if (strcmp(m->desc, "flash") == 0) {
|
||||
rval = avr910_paged_write_flash(pgm, p, m, page_size, addr, n_bytes);
|
||||
} else if (strcmp(m->desc, "eeprom") == 0) {
|
||||
rval = avr910_paged_write_eeprom(pgm, p, m, page_size, addr, n_bytes);
|
||||
} else {
|
||||
rval = -2;
|
||||
}
|
||||
}
|
||||
|
||||
if (PDATA(pgm)->use_blockmode == 1) {
|
||||
unsigned int max_addr = addr + n_bytes;
|
||||
char *cmd;
|
||||
unsigned int blocksize = PDATA(pgm)->buffersize;
|
||||
int wr_size;
|
||||
|
||||
if (strcmp(m->desc, "flash") && strcmp(m->desc, "eeprom"))
|
||||
return -2;
|
||||
|
||||
if (m->desc[0] == 'e') {
|
||||
blocksize = 1; /* Write to eeprom single bytes only */
|
||||
wr_size = 1;
|
||||
} else {
|
||||
wr_size = 2;
|
||||
}
|
||||
|
||||
avr910_set_addr(pgm, addr / wr_size);
|
||||
|
||||
cmd = malloc(4 + blocksize);
|
||||
if (!cmd) return -1;
|
||||
|
||||
cmd[0] = 'B';
|
||||
cmd[3] = toupper((int)(m->desc[0]));
|
||||
|
||||
while (addr < max_addr) {
|
||||
if ((max_addr - addr) < blocksize) {
|
||||
blocksize = max_addr - addr;
|
||||
};
|
||||
memcpy(&cmd[4], &m->buf[addr], blocksize);
|
||||
cmd[1] = (blocksize >> 8) & 0xff;
|
||||
cmd[2] = blocksize & 0xff;
|
||||
|
||||
avr910_send(pgm, cmd, 4 + blocksize);
|
||||
avr910_vfy_cmd_sent(pgm, "write block");
|
||||
|
||||
addr += blocksize;
|
||||
} /* while */
|
||||
free(cmd);
|
||||
|
||||
rval = addr;
|
||||
}
|
||||
return rval;
|
||||
}
|
||||
|
||||
|
||||
static int avr910_paged_load(PROGRAMMER * pgm, AVRPART * p, AVRMEM * m,
|
||||
unsigned int page_size,
|
||||
unsigned int addr, unsigned int n_bytes)
|
||||
{
|
||||
char cmd[4];
|
||||
int rd_size;
|
||||
unsigned int max_addr;
|
||||
char buf[2];
|
||||
int rval=0;
|
||||
|
||||
max_addr = addr + n_bytes;
|
||||
|
||||
if (strcmp(m->desc, "flash") == 0) {
|
||||
cmd[0] = 'R';
|
||||
rd_size = 2; /* read two bytes per addr */
|
||||
} else if (strcmp(m->desc, "eeprom") == 0) {
|
||||
cmd[0] = 'd';
|
||||
rd_size = 1;
|
||||
} else {
|
||||
return -2;
|
||||
}
|
||||
|
||||
if (PDATA(pgm)->use_blockmode) {
|
||||
/* use buffered mode */
|
||||
int blocksize = PDATA(pgm)->buffersize;
|
||||
|
||||
cmd[0] = 'g';
|
||||
cmd[3] = toupper((int)(m->desc[0]));
|
||||
|
||||
avr910_set_addr(pgm, addr / rd_size);
|
||||
|
||||
while (addr < max_addr) {
|
||||
if ((max_addr - addr) < blocksize) {
|
||||
blocksize = max_addr - addr;
|
||||
}
|
||||
cmd[1] = (blocksize >> 8) & 0xff;
|
||||
cmd[2] = blocksize & 0xff;
|
||||
|
||||
avr910_send(pgm, cmd, 4);
|
||||
avr910_recv(pgm, (char *)&m->buf[addr], blocksize);
|
||||
|
||||
addr += blocksize;
|
||||
}
|
||||
|
||||
rval = addr;
|
||||
} else {
|
||||
|
||||
avr910_set_addr(pgm, addr / rd_size);
|
||||
|
||||
while (addr < max_addr) {
|
||||
avr910_send(pgm, cmd, 1);
|
||||
if (rd_size == 2) {
|
||||
/* The 'R' command returns two bytes, MSB first, we need to put the data
|
||||
into the memory buffer LSB first. */
|
||||
avr910_recv(pgm, buf, 2);
|
||||
m->buf[addr] = buf[1]; /* LSB */
|
||||
m->buf[addr + 1] = buf[0]; /* MSB */
|
||||
}
|
||||
else {
|
||||
avr910_recv(pgm, (char *)&m->buf[addr], 1);
|
||||
}
|
||||
|
||||
addr += rd_size;
|
||||
|
||||
if (PDATA(pgm)->has_auto_incr_addr != 'Y') {
|
||||
avr910_set_addr(pgm, addr / rd_size);
|
||||
}
|
||||
}
|
||||
|
||||
rval = addr;
|
||||
}
|
||||
|
||||
return rval;
|
||||
}
|
||||
|
||||
/* Signature byte reads are always 3 bytes. */
|
||||
|
||||
static int avr910_read_sig_bytes(PROGRAMMER * pgm, AVRPART * p, AVRMEM * m)
|
||||
{
|
||||
unsigned char tmp;
|
||||
|
||||
if (m->size < 3) {
|
||||
avrdude_message(MSG_INFO, "%s: memsize too small for sig byte read", progname);
|
||||
return -1;
|
||||
}
|
||||
|
||||
avr910_send(pgm, "s", 1);
|
||||
avr910_recv(pgm, (char *)m->buf, 3);
|
||||
/* Returned signature has wrong order. */
|
||||
tmp = m->buf[2];
|
||||
m->buf[2] = m->buf[0];
|
||||
m->buf[0] = tmp;
|
||||
|
||||
return 3;
|
||||
}
|
||||
|
||||
const char avr910_desc[] = "Serial programmers using protocol described in application note AVR910";
|
||||
|
||||
void avr910_initpgm(PROGRAMMER * pgm)
|
||||
{
|
||||
strcpy(pgm->type, "avr910");
|
||||
|
||||
/*
|
||||
* mandatory functions
|
||||
*/
|
||||
pgm->initialize = avr910_initialize;
|
||||
pgm->display = avr910_display;
|
||||
pgm->enable = avr910_enable;
|
||||
pgm->disable = avr910_disable;
|
||||
pgm->program_enable = avr910_program_enable;
|
||||
pgm->chip_erase = avr910_chip_erase;
|
||||
pgm->cmd = avr910_cmd;
|
||||
pgm->open = avr910_open;
|
||||
pgm->close = avr910_close;
|
||||
|
||||
/*
|
||||
* optional functions
|
||||
*/
|
||||
|
||||
pgm->write_byte = avr910_write_byte;
|
||||
pgm->read_byte = avr910_read_byte;
|
||||
|
||||
pgm->paged_write = avr910_paged_write;
|
||||
pgm->paged_load = avr910_paged_load;
|
||||
|
||||
pgm->read_sig_bytes = avr910_read_sig_bytes;
|
||||
|
||||
pgm->parseextparams = avr910_parseextparms;
|
||||
pgm->setup = avr910_setup;
|
||||
pgm->teardown = avr910_teardown;
|
||||
}
|
||||
35
src/avr910.h
Normal file
35
src/avr910.h
Normal file
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* avrdude - A Downloader/Uploader for AVR device programmers
|
||||
* Copyright (C) 2003-2004 Theodore A. Roth <troth@openavr.org>
|
||||
*
|
||||
* 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/* $Id$ */
|
||||
|
||||
#ifndef avr910_h
|
||||
#define avr910_h
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
extern const char avr910_desc[];
|
||||
void avr910_initpgm (PROGRAMMER * pgm);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* avr910_h */
|
||||
1216
src/avrdude.1
Normal file
1216
src/avrdude.1
Normal file
File diff suppressed because it is too large
Load Diff
17132
src/avrdude.conf.in
Normal file
17132
src/avrdude.conf.in
Normal file
File diff suppressed because it is too large
Load Diff
63
src/avrdude.h
Normal file
63
src/avrdude.h
Normal file
@@ -0,0 +1,63 @@
|
||||
/*
|
||||
* avrdude - A Downloader/Uploader for AVR device programmers
|
||||
* Copyright (C) 2007 Joerg Wunsch
|
||||
*
|
||||
* 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/* $Id$ */
|
||||
|
||||
#ifndef avrdude_h
|
||||
#define avrdude_h
|
||||
|
||||
extern char * progname; /* name of program, for messages */
|
||||
extern char progbuf[]; /* spaces same length as progname */
|
||||
|
||||
extern int ovsigck; /* override signature check (-F) */
|
||||
extern int verbose; /* verbosity level (-v, -vv, ...) */
|
||||
extern int quell_progress; /* quiteness level (-q, -qq) */
|
||||
|
||||
int avrdude_message(const int msglvl, const char *format, ...);
|
||||
|
||||
#define MSG_INFO (0) /* no -v option, can be supressed with -qq */
|
||||
#define MSG_NOTICE (1) /* displayed with -v */
|
||||
#define MSG_NOTICE2 (2) /* displayed with -vv, used rarely */
|
||||
#define MSG_DEBUG (3) /* displayed with -vvv */
|
||||
#define MSG_TRACE (4) /* displayed with -vvvv, show trace commuication */
|
||||
#define MSG_TRACE2 (5) /* displayed with -vvvvv */
|
||||
|
||||
#if defined(WIN32NATIVE)
|
||||
|
||||
#include "ac_cfg.h"
|
||||
#include <windows.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#if !defined(HAVE_USLEEP)
|
||||
int usleep(unsigned int us);
|
||||
#endif
|
||||
|
||||
#if !defined(HAVE_GETTIMEOFDAY)
|
||||
struct timezone;
|
||||
int gettimeofday(struct timeval *tv, struct timezone *tz);
|
||||
#endif /* HAVE_GETTIMEOFDAY */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif /* defined(WIN32NATIVE) */
|
||||
|
||||
#endif
|
||||
113
src/avrdude.spec.in
Normal file
113
src/avrdude.spec.in
Normal file
@@ -0,0 +1,113 @@
|
||||
## -*- mode: rpm-spec; -*-
|
||||
##
|
||||
## $Id$
|
||||
##
|
||||
## @configure_input@
|
||||
##
|
||||
|
||||
%define debug_package %{nil}
|
||||
|
||||
%define _with_docs 1
|
||||
%{?_without_docs: %define _with_docs 0}
|
||||
|
||||
Summary: AVRDUDE is software for programming Atmel AVR Microcontrollers.
|
||||
Name: avrdude
|
||||
Version: @VERSION@
|
||||
Release: 1
|
||||
URL: http://savannah.nongnu.org/projects/avrdude
|
||||
Source0: %{name}-%{version}.tar.gz
|
||||
License: GPL
|
||||
Group: Development/Tools
|
||||
BuildRoot: %{_tmppath}/%{name}-%{version}-root
|
||||
|
||||
%description
|
||||
AVRDUDE is software for programming Atmel AVR Microcontrollers.
|
||||
|
||||
%if %{_with_docs}
|
||||
## The avrdude-docs subpackage
|
||||
%package docs
|
||||
Summary: Documentation for AVRDUDE.
|
||||
Group: Documentation
|
||||
%description docs
|
||||
Documentation for avrdude in info, html, postscript and pdf formats.
|
||||
%endif
|
||||
|
||||
%prep
|
||||
%setup -q
|
||||
|
||||
%build
|
||||
|
||||
./configure --prefix=%{_prefix} --sysconfdir=/etc --mandir=%{_mandir} \
|
||||
--infodir=%{_infodir} \
|
||||
%if %{_with_docs}
|
||||
--enable-doc=yes
|
||||
%else
|
||||
--enable-doc=no
|
||||
%endif
|
||||
|
||||
make
|
||||
|
||||
%install
|
||||
rm -rf $RPM_BUILD_ROOT
|
||||
make prefix=$RPM_BUILD_ROOT%{_prefix} \
|
||||
sysconfdir=$RPM_BUILD_ROOT/etc \
|
||||
mandir=$RPM_BUILD_ROOT%{_mandir} \
|
||||
infodir=$RPM_BUILD_ROOT%{_infodir} \
|
||||
install
|
||||
|
||||
rm -rf $RPM_BUILD_ROOT%{_datadir}/doc/%{name}-%{version}
|
||||
rm -f $RPM_BUILD_ROOT%{_infodir}/dir
|
||||
|
||||
%clean
|
||||
rm -rf $RPM_BUILD_ROOT
|
||||
|
||||
%if %{_with_docs}
|
||||
%post docs
|
||||
[ -f %{_infodir}/avrdude.info ] && \
|
||||
/sbin/install-info %{_infodir}/avrdude.info %{_infodir}/dir || :
|
||||
[ -f %{_infodir}/avrdude.info.gz ] && \
|
||||
/sbin/install-info %{_infodir}/avrdude.info.gz %{_infodir}/dir || :
|
||||
|
||||
%preun docs
|
||||
if [ $1 = 0 ]; then
|
||||
[ -f %{_infodir}/avrdude.info ] && \
|
||||
/sbin/install-info --delete %{_infodir}/avrdude.info %{_infodir}/dir || :
|
||||
[ -f %{_infodir}/avrdude.info.gz ] && \
|
||||
/sbin/install-info --delete %{_infodir}/avrdude.info.gz %{_infodir}/dir || :
|
||||
fi
|
||||
%endif
|
||||
|
||||
%files
|
||||
%defattr(-,root,root)
|
||||
%{_prefix}/bin/avrdude
|
||||
%{_mandir}/man1/avrdude.1.gz
|
||||
%attr(0644,root,root) %config /etc/avrdude.conf
|
||||
|
||||
%if %{_with_docs}
|
||||
%files docs
|
||||
%doc %{_infodir}/*info*
|
||||
%doc doc/avrdude-html/*.html
|
||||
%doc doc/TODO
|
||||
%doc doc/avrdude.ps
|
||||
%doc doc/avrdude.pdf
|
||||
%endif
|
||||
|
||||
%changelog
|
||||
* Fri Sep 23 2005 Galen Seitz <galens@seitzassoc.com>
|
||||
- Default to enable-doc=yes during configure.
|
||||
- Move info file to docs package.
|
||||
- Make building of docs package conditional. Basic idea copied from avr-gcc.
|
||||
|
||||
* Wed Aug 27 2003 Theodore A. Roth <troth@openavr.org>
|
||||
[Thanks to Artur Lipowski <LAL@pro.onet.pl>]
|
||||
- Do not build debug package.
|
||||
- Remove files not packaged to quell RH9 rpmbuild complaints.
|
||||
|
||||
* Wed Mar 05 2003 Theodore A. Roth <troth@openavr.org>
|
||||
- Add docs sub-package.
|
||||
- Add %post and %preun scriptlets for handling info files.
|
||||
|
||||
* Wed Feb 26 2003 Theodore A. Roth <troth@openavr.org>
|
||||
- Initial build.
|
||||
|
||||
|
||||
1274
src/avrftdi.c
Normal file
1274
src/avrftdi.c
Normal file
File diff suppressed because it is too large
Load Diff
40
src/avrftdi.h
Normal file
40
src/avrftdi.h
Normal file
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/* $Id$ */
|
||||
|
||||
#ifndef avrftdi_h
|
||||
#define avrftdi_h
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
extern const char avrftdi_desc[];
|
||||
void avrftdi_initpgm (PROGRAMMER * pgm);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
86
src/avrftdi_private.h
Normal file
86
src/avrftdi_private.h
Normal file
@@ -0,0 +1,86 @@
|
||||
#pragma once
|
||||
#include "ac_cfg.h"
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#if defined(HAVE_LIBFTDI1) && defined(HAVE_LIBUSB_1_0)
|
||||
# if defined(HAVE_LIBUSB_1_0_LIBUSB_H)
|
||||
# include <libusb-1.0/libusb.h>
|
||||
# else
|
||||
# include <libusb.h>
|
||||
# endif
|
||||
# include <libftdi1/ftdi.h>
|
||||
# undef HAVE_LIBFTDI_TYPE_232H
|
||||
# define HAVE_LIBFTDI_TYPE_232H 1
|
||||
#elif defined(HAVE_LIBFTDI) && defined(HAVE_USB_H)
|
||||
/* ftdi.h includes usb.h */
|
||||
#include <ftdi.h>
|
||||
#else
|
||||
#warning No libftdi or libusb support. Install libftdi1/libusb-1.0 or libftdi/libusb and run configure/make again.
|
||||
#define DO_NOT_BUILD_AVRFTDI
|
||||
#endif
|
||||
|
||||
#ifndef DO_NOT_BUILD_AVRFTDI
|
||||
|
||||
enum { ERR, WARN, INFO, DEBUG, TRACE };
|
||||
|
||||
#define __log(lvl, fmt, ...) \
|
||||
do { \
|
||||
avrftdi_log(lvl, __func__, __LINE__, fmt, ##__VA_ARGS__); \
|
||||
} while(0)
|
||||
|
||||
|
||||
#define log_err(fmt, ...) __log(ERR, fmt, ##__VA_ARGS__)
|
||||
#define log_warn(fmt, ...) __log(WARN, fmt, ##__VA_ARGS__)
|
||||
#define log_info(fmt, ...) __log(INFO, fmt, ##__VA_ARGS__)
|
||||
#define log_debug(fmt, ...) __log(DEBUG, fmt, ##__VA_ARGS__)
|
||||
#define log_trace(fmt, ...) __log(TRACE, fmt, ##__VA_ARGS__)
|
||||
|
||||
#define E(x, ftdi) \
|
||||
do { \
|
||||
if ((x)) \
|
||||
{ \
|
||||
avrdude_message(MSG_INFO, "%s:%d %s() %s: %s (%d)\n\t%s\n", \
|
||||
__FILE__, __LINE__, __FUNCTION__, \
|
||||
#x, strerror(errno), errno, ftdi_get_error_string(ftdi)); \
|
||||
return -1; \
|
||||
} \
|
||||
} while(0)
|
||||
|
||||
#define E_VOID(x, ftdi) \
|
||||
do { \
|
||||
if ((x)) \
|
||||
{ \
|
||||
avrdude_message(MSG_INFO, "%s:%d %s() %s: %s (%d)\n\t%s\n", \
|
||||
__FILE__, __LINE__, __FUNCTION__, \
|
||||
#x, strerror(errno), errno, ftdi_get_error_string(ftdi)); \
|
||||
} \
|
||||
} while(0)
|
||||
|
||||
|
||||
#define to_pdata(pgm) \
|
||||
((avrftdi_t *)((pgm)->cookie))
|
||||
|
||||
typedef struct avrftdi_s {
|
||||
/* pointer to struct maintained by libftdi to identify the device */
|
||||
struct ftdi_context* ftdic;
|
||||
/* bitmask of values for pins. bit 0 represents pin 0 ([A|B]DBUS0) */
|
||||
uint16_t pin_value;
|
||||
/* bitmask of pin direction. a '1' make a pin an output.
|
||||
* bit 0 corresponds to pin 0. */
|
||||
uint16_t pin_direction;
|
||||
/* don't know. not useful. someone put it in. */
|
||||
uint16_t led_mask;
|
||||
/* total number of pins supported by a programmer. varies with FTDI chips */
|
||||
int pin_limit;
|
||||
/* internal RX buffer of the device. needed for INOUT transfers */
|
||||
int rx_buffer_size;
|
||||
int tx_buffer_size;
|
||||
/* use bitbanging instead of mpsse spi */
|
||||
bool use_bitbanging;
|
||||
} avrftdi_t;
|
||||
|
||||
void avrftdi_log(int level, const char * func, int line, const char * fmt, ...);
|
||||
|
||||
#endif /* DO_NOT_BUILD_AVRFDTI */
|
||||
|
||||
254
src/avrftdi_tpi.c
Normal file
254
src/avrftdi_tpi.c
Normal file
@@ -0,0 +1,254 @@
|
||||
#include "ac_cfg.h"
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "avrdude.h"
|
||||
#include "libavrdude.h"
|
||||
|
||||
#include "usbasp.h"
|
||||
|
||||
#include "avrftdi_tpi.h"
|
||||
#include "avrftdi_private.h"
|
||||
|
||||
#ifndef DO_NOT_BUILD_AVRFTDI
|
||||
|
||||
static void avrftdi_tpi_disable(PROGRAMMER *);
|
||||
static int avrftdi_tpi_program_enable(PROGRAMMER * pgm, AVRPART * p);
|
||||
|
||||
#ifdef notyet
|
||||
static void
|
||||
avrftdi_debug_frame(uint16_t frame)
|
||||
{
|
||||
static char bit_name[] = "IDLES01234567PSS";
|
||||
//static char bit_name[] = "SSP76543210SELDI";
|
||||
char line0[34], line1[34], line2[34];
|
||||
int bit, pos;
|
||||
|
||||
for(bit = 0; bit < 16; bit++)
|
||||
{
|
||||
pos = 16 - bit - 1;
|
||||
if(frame & (1 << pos))
|
||||
{
|
||||
line0[2*pos] = '_';
|
||||
line0[2*pos+1] = ' ';
|
||||
|
||||
line2[2*pos] = ' ';
|
||||
line2[2*pos+1] = ' ';
|
||||
}
|
||||
else
|
||||
{
|
||||
line0[2*pos] = ' ';
|
||||
line0[2*pos+1] = ' ';
|
||||
|
||||
line2[2*pos] = '-';
|
||||
line2[2*pos+1] = ' ';
|
||||
}
|
||||
|
||||
line1[2*pos] = bit_name[pos];
|
||||
line1[2*pos+1] = ' ';
|
||||
|
||||
}
|
||||
|
||||
line0[32] = 0;
|
||||
line1[32] = 0;
|
||||
line2[32] = 0;
|
||||
|
||||
log_debug("%s\n", line0);
|
||||
log_debug("%s\n", line1);
|
||||
//log_debug("%s\n", line2);
|
||||
}
|
||||
#endif /* notyet */
|
||||
|
||||
int
|
||||
avrftdi_tpi_initialize(PROGRAMMER * pgm, AVRPART * p)
|
||||
{
|
||||
int ret;
|
||||
|
||||
avrftdi_t* pdata = to_pdata(pgm);
|
||||
unsigned char buf[] = { MPSSE_DO_WRITE | MPSSE_WRITE_NEG | MPSSE_LSB, 0x01, 0x00, 0xff, 0xff };
|
||||
|
||||
log_info("Using TPI interface\n");
|
||||
|
||||
pgm->program_enable = avrftdi_tpi_program_enable;
|
||||
pgm->cmd_tpi = avrftdi_cmd_tpi;
|
||||
pgm->chip_erase = avr_tpi_chip_erase;
|
||||
pgm->disable = avrftdi_tpi_disable;
|
||||
|
||||
pgm->paged_load = NULL;
|
||||
pgm->paged_write = NULL;
|
||||
|
||||
log_info("Setting /Reset pin low\n");
|
||||
pgm->setpin(pgm, PIN_AVR_RESET, OFF);
|
||||
pgm->setpin(pgm, PIN_AVR_SCK, OFF);
|
||||
pgm->setpin(pgm, PIN_AVR_MOSI, ON);
|
||||
usleep(20 * 1000);
|
||||
|
||||
pgm->setpin(pgm, PIN_AVR_RESET, ON);
|
||||
/* worst case 128ms */
|
||||
usleep(2 * 128 * 1000);
|
||||
|
||||
/*setting rst back to 0 */
|
||||
pgm->setpin(pgm, PIN_AVR_RESET, OFF);
|
||||
/*wait at least 20ms bevor issuing spi commands to avr */
|
||||
usleep(20 * 1000);
|
||||
|
||||
log_info("Sending 16 init clock cycles ...\n");
|
||||
ret = ftdi_write_data(pdata->ftdic, buf, sizeof(buf));
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#define TPI_PARITY_MASK 0x2000
|
||||
|
||||
static uint16_t
|
||||
tpi_byte2frame(uint8_t byte)
|
||||
{
|
||||
uint16_t frame = 0xc00f;
|
||||
int parity = __builtin_popcount(byte) & 1;
|
||||
|
||||
frame |= ((byte << 5) & 0x1fe0);
|
||||
|
||||
if(parity)
|
||||
frame |= TPI_PARITY_MASK;
|
||||
|
||||
return frame;
|
||||
}
|
||||
|
||||
static int
|
||||
tpi_frame2byte(uint16_t frame, uint8_t * byte)
|
||||
{
|
||||
/* drop idle and start bit(s) */
|
||||
*byte = (frame >> 5) & 0xff;
|
||||
|
||||
int parity = __builtin_popcount(*byte) & 1;
|
||||
int parity_rcvd = (frame & TPI_PARITY_MASK) ? 1 : 0;
|
||||
|
||||
return parity != parity_rcvd;
|
||||
}
|
||||
|
||||
#ifdef notyet
|
||||
static int
|
||||
avrftdi_tpi_break(PROGRAMMER * pgm)
|
||||
{
|
||||
unsigned char buffer[] = { MPSSE_DO_WRITE | MPSSE_WRITE_NEG | MPSSE_LSB, 1, 0, 0, 0 };
|
||||
E(ftdi_write_data(to_pdata(pgm)->ftdic, buffer, sizeof(buffer)) != sizeof(buffer), to_pdata(pgm)->ftdic);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif /* notyet */
|
||||
|
||||
static int
|
||||
avrftdi_tpi_write_byte(PROGRAMMER * pgm, unsigned char byte)
|
||||
{
|
||||
uint16_t frame;
|
||||
|
||||
struct ftdi_context* ftdic = to_pdata(pgm)->ftdic;
|
||||
|
||||
unsigned char buffer[] = { MPSSE_DO_WRITE | MPSSE_WRITE_NEG | MPSSE_LSB, 1, 0, 0, 0 };
|
||||
|
||||
frame = tpi_byte2frame(byte);
|
||||
|
||||
buffer[3] = frame & 0xff;
|
||||
buffer[4] = frame >> 8;
|
||||
|
||||
log_trace("Byte %02x, frame: %04x, MPSSE: 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x\n",
|
||||
byte, frame, buffer[0], buffer[1], buffer[2], buffer[3], buffer[4]);
|
||||
|
||||
//avrftdi_debug_frame(frame);
|
||||
|
||||
E(ftdi_write_data(ftdic, buffer, sizeof(buffer)) != sizeof(buffer), ftdic);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define TPI_FRAME_SIZE 12
|
||||
#define TPI_IDLE_BITS 2
|
||||
|
||||
static int
|
||||
avrftdi_tpi_read_byte(PROGRAMMER * pgm, unsigned char * byte)
|
||||
{
|
||||
uint16_t frame;
|
||||
|
||||
/* use 2 guard bits, 2 default idle bits + 12 frame bits = 16 bits total */
|
||||
const int bytes = 3;
|
||||
int err, i = 0;
|
||||
|
||||
unsigned char buffer[4];
|
||||
|
||||
buffer[0] = MPSSE_DO_READ | MPSSE_LSB;
|
||||
buffer[1] = (bytes-1) & 0xff;
|
||||
buffer[2] = ((bytes-1) >> 8) & 0xff;
|
||||
buffer[3] = SEND_IMMEDIATE;
|
||||
|
||||
log_trace("MPSSE: 0x%02x 0x%02x 0x%02x 0x%02x (Read frame)\n",
|
||||
buffer[0], buffer[1], buffer[2], buffer[3]);
|
||||
|
||||
ftdi_write_data(to_pdata(pgm)->ftdic, buffer, 4);
|
||||
|
||||
memset(buffer, 0, sizeof(buffer));
|
||||
|
||||
i = 0;
|
||||
do {
|
||||
int err = ftdi_read_data(to_pdata(pgm)->ftdic, &buffer[i], bytes - i);
|
||||
E(err < 0, to_pdata(pgm)->ftdic);
|
||||
i += err;
|
||||
} while(i < bytes);
|
||||
|
||||
|
||||
log_trace("MPSSE: 0x%02x 0x%02x 0x%02x 0x%02x (Read frame)\n",
|
||||
buffer[0], buffer[1], buffer[2], buffer[3]);
|
||||
|
||||
|
||||
frame = buffer[0] | (buffer[1] << 8);
|
||||
|
||||
err = tpi_frame2byte(frame, byte);
|
||||
log_trace("Frame: 0x%04x, byte: 0x%02x\n", frame, *byte);
|
||||
|
||||
//avrftdi_debug_frame(frame);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static int
|
||||
avrftdi_tpi_program_enable(PROGRAMMER * pgm, AVRPART * p)
|
||||
{
|
||||
return avr_tpi_program_enable(pgm, p, TPIPCR_GT_2b);
|
||||
}
|
||||
|
||||
int
|
||||
avrftdi_cmd_tpi(PROGRAMMER * pgm, const unsigned char *cmd, int cmd_len,
|
||||
unsigned char *res, int res_len)
|
||||
{
|
||||
int i, err = 0;
|
||||
|
||||
for(i = 0; i < cmd_len; i++)
|
||||
{
|
||||
err = avrftdi_tpi_write_byte(pgm, cmd[i]);
|
||||
if(err)
|
||||
return err;
|
||||
}
|
||||
|
||||
for(i = 0; i < res_len; i++)
|
||||
{
|
||||
err = avrftdi_tpi_read_byte(pgm, &res[i]);
|
||||
if(err)
|
||||
return err;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
avrftdi_tpi_disable(PROGRAMMER * pgm)
|
||||
{
|
||||
unsigned char cmd[] = {TPI_OP_SSTCS(TPIPCR), 0};
|
||||
pgm->cmd_tpi(pgm, cmd, sizeof(cmd), NULL, 0);
|
||||
|
||||
log_info("Leaving Programming mode.\n");
|
||||
}
|
||||
|
||||
#endif /* DO_NOT_BUILD_AVRFTDI */
|
||||
|
||||
9
src/avrftdi_tpi.h
Normal file
9
src/avrftdi_tpi.h
Normal file
@@ -0,0 +1,9 @@
|
||||
#pragma once
|
||||
|
||||
//int avrftdi_tpi_write_byte(PROGRAMMER * pgm, unsigned char byte);
|
||||
//int avrftdi_tpi_read_byte(PROGRAMMER * pgm, unsigned char * byte);
|
||||
int avrftdi_cmd_tpi(PROGRAMMER * pgm, const unsigned char *cmd, int cmd_len,
|
||||
unsigned char *res, int res_len);
|
||||
int avrftdi_tpi_initialize(PROGRAMMER * pgm, AVRPART * p);
|
||||
|
||||
|
||||
681
src/avrpart.c
Normal file
681
src/avrpart.c
Normal file
@@ -0,0 +1,681 @@
|
||||
|
||||
/*
|
||||
* avrdude - A Downloader/Uploader for AVR device programmers
|
||||
* Copyright (C) 2000-2004 Brian S. Dean <bsd@bsdhome.com>
|
||||
* Copyright (C) 2006 Joerg Wunsch <j@uriah.heep.sax.de>
|
||||
*
|
||||
* 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/* $Id$ */
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "avrdude.h"
|
||||
#include "libavrdude.h"
|
||||
|
||||
/***
|
||||
*** Elementary functions dealing with OPCODE structures
|
||||
***/
|
||||
|
||||
OPCODE * avr_new_opcode(void)
|
||||
{
|
||||
OPCODE * m;
|
||||
|
||||
m = (OPCODE *)malloc(sizeof(*m));
|
||||
if (m == NULL) {
|
||||
avrdude_message(MSG_INFO, "avr_new_opcode(): out of memory\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
memset(m, 0, sizeof(*m));
|
||||
|
||||
return m;
|
||||
}
|
||||
|
||||
static OPCODE * avr_dup_opcode(OPCODE * op)
|
||||
{
|
||||
OPCODE * m;
|
||||
|
||||
/* this makes life easier */
|
||||
if (op == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
m = (OPCODE *)malloc(sizeof(*m));
|
||||
if (m == NULL) {
|
||||
avrdude_message(MSG_INFO, "avr_dup_opcode(): out of memory\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
memcpy(m, op, sizeof(*m));
|
||||
|
||||
return m;
|
||||
}
|
||||
|
||||
void avr_free_opcode(OPCODE * op)
|
||||
{
|
||||
free(op);
|
||||
}
|
||||
|
||||
/*
|
||||
* avr_set_bits()
|
||||
*
|
||||
* Set instruction bits in the specified command based on the opcode.
|
||||
*/
|
||||
int avr_set_bits(OPCODE * op, unsigned char * cmd)
|
||||
{
|
||||
int i, j, bit;
|
||||
unsigned char mask;
|
||||
|
||||
for (i=0; i<32; i++) {
|
||||
if (op->bit[i].type == AVR_CMDBIT_VALUE) {
|
||||
j = 3 - i / 8;
|
||||
bit = i % 8;
|
||||
mask = 1 << bit;
|
||||
if (op->bit[i].value)
|
||||
cmd[j] = cmd[j] | mask;
|
||||
else
|
||||
cmd[j] = cmd[j] & ~mask;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* avr_set_addr()
|
||||
*
|
||||
* Set address bits in the specified command based on the opcode, and
|
||||
* the address.
|
||||
*/
|
||||
int avr_set_addr(OPCODE * op, unsigned char * cmd, unsigned long addr)
|
||||
{
|
||||
int i, j, bit;
|
||||
unsigned long value;
|
||||
unsigned char mask;
|
||||
|
||||
for (i=0; i<32; i++) {
|
||||
if (op->bit[i].type == AVR_CMDBIT_ADDRESS) {
|
||||
j = 3 - i / 8;
|
||||
bit = i % 8;
|
||||
mask = 1 << bit;
|
||||
value = addr >> op->bit[i].bitno & 0x01;
|
||||
if (value)
|
||||
cmd[j] = cmd[j] | mask;
|
||||
else
|
||||
cmd[j] = cmd[j] & ~mask;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* avr_set_input()
|
||||
*
|
||||
* Set input data bits in the specified command based on the opcode,
|
||||
* and the data byte.
|
||||
*/
|
||||
int avr_set_input(OPCODE * op, unsigned char * cmd, unsigned char data)
|
||||
{
|
||||
int i, j, bit;
|
||||
unsigned char value;
|
||||
unsigned char mask;
|
||||
|
||||
for (i=0; i<32; i++) {
|
||||
if (op->bit[i].type == AVR_CMDBIT_INPUT) {
|
||||
j = 3 - i / 8;
|
||||
bit = i % 8;
|
||||
mask = 1 << bit;
|
||||
value = data >> op->bit[i].bitno & 0x01;
|
||||
if (value)
|
||||
cmd[j] = cmd[j] | mask;
|
||||
else
|
||||
cmd[j] = cmd[j] & ~mask;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* avr_get_output()
|
||||
*
|
||||
* Retreive output data bits from the command results based on the
|
||||
* opcode data.
|
||||
*/
|
||||
int avr_get_output(OPCODE * op, unsigned char * res, unsigned char * data)
|
||||
{
|
||||
int i, j, bit;
|
||||
unsigned char value;
|
||||
unsigned char mask;
|
||||
|
||||
for (i=0; i<32; i++) {
|
||||
if (op->bit[i].type == AVR_CMDBIT_OUTPUT) {
|
||||
j = 3 - i / 8;
|
||||
bit = i % 8;
|
||||
mask = 1 << bit;
|
||||
value = ((res[j] & mask) >> bit) & 0x01;
|
||||
value = value << op->bit[i].bitno;
|
||||
if (value)
|
||||
*data = *data | value;
|
||||
else
|
||||
*data = *data & ~value;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* avr_get_output_index()
|
||||
*
|
||||
* Calculate the byte number of the output data based on the
|
||||
* opcode data.
|
||||
*/
|
||||
int avr_get_output_index(OPCODE * op)
|
||||
{
|
||||
int i, j;
|
||||
|
||||
for (i=0; i<32; i++) {
|
||||
if (op->bit[i].type == AVR_CMDBIT_OUTPUT) {
|
||||
j = 3 - i / 8;
|
||||
return j;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
static char * avr_op_str(int op)
|
||||
{
|
||||
switch (op) {
|
||||
case AVR_OP_READ : return "READ"; break;
|
||||
case AVR_OP_WRITE : return "WRITE"; break;
|
||||
case AVR_OP_READ_LO : return "READ_LO"; break;
|
||||
case AVR_OP_READ_HI : return "READ_HI"; break;
|
||||
case AVR_OP_WRITE_LO : return "WRITE_LO"; break;
|
||||
case AVR_OP_WRITE_HI : return "WRITE_HI"; break;
|
||||
case AVR_OP_LOADPAGE_LO : return "LOADPAGE_LO"; break;
|
||||
case AVR_OP_LOADPAGE_HI : return "LOADPAGE_HI"; break;
|
||||
case AVR_OP_LOAD_EXT_ADDR : return "LOAD_EXT_ADDR"; break;
|
||||
case AVR_OP_WRITEPAGE : return "WRITEPAGE"; break;
|
||||
case AVR_OP_CHIP_ERASE : return "CHIP_ERASE"; break;
|
||||
case AVR_OP_PGM_ENABLE : return "PGM_ENABLE"; break;
|
||||
default : return "<unknown opcode>"; break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static char * bittype(int type)
|
||||
{
|
||||
switch (type) {
|
||||
case AVR_CMDBIT_IGNORE : return "IGNORE"; break;
|
||||
case AVR_CMDBIT_VALUE : return "VALUE"; break;
|
||||
case AVR_CMDBIT_ADDRESS : return "ADDRESS"; break;
|
||||
case AVR_CMDBIT_INPUT : return "INPUT"; break;
|
||||
case AVR_CMDBIT_OUTPUT : return "OUTPUT"; break;
|
||||
default : return "<unknown bit type>"; break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***
|
||||
*** Elementary functions dealing with AVRMEM structures
|
||||
***/
|
||||
|
||||
AVRMEM * avr_new_memtype(void)
|
||||
{
|
||||
AVRMEM * m;
|
||||
|
||||
m = (AVRMEM *)malloc(sizeof(*m));
|
||||
if (m == NULL) {
|
||||
avrdude_message(MSG_INFO, "avr_new_memtype(): out of memory\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
memset(m, 0, sizeof(*m));
|
||||
m->page_size = 1; // ensure not 0
|
||||
|
||||
return m;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Allocate and initialize memory buffers for each of the device's
|
||||
* defined memory regions.
|
||||
*/
|
||||
int avr_initmem(AVRPART * p)
|
||||
{
|
||||
LNODEID ln;
|
||||
AVRMEM * m;
|
||||
|
||||
for (ln=lfirst(p->mem); ln; ln=lnext(ln)) {
|
||||
m = ldata(ln);
|
||||
m->buf = (unsigned char *) malloc(m->size);
|
||||
if (m->buf == NULL) {
|
||||
avrdude_message(MSG_INFO, "%s: can't alloc buffer for %s size of %d bytes\n",
|
||||
progname, m->desc, m->size);
|
||||
return -1;
|
||||
}
|
||||
m->tags = (unsigned char *) malloc(m->size);
|
||||
if (m->tags == NULL) {
|
||||
avrdude_message(MSG_INFO, "%s: can't alloc buffer for %s size of %d bytes\n",
|
||||
progname, m->desc, m->size);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
AVRMEM * avr_dup_mem(AVRMEM * m)
|
||||
{
|
||||
AVRMEM * n;
|
||||
int i;
|
||||
|
||||
n = avr_new_memtype();
|
||||
|
||||
*n = *m;
|
||||
|
||||
if (m->buf != NULL) {
|
||||
n->buf = (unsigned char *)malloc(n->size);
|
||||
if (n->buf == NULL) {
|
||||
avrdude_message(MSG_INFO, "avr_dup_mem(): out of memory (memsize=%d)\n",
|
||||
n->size);
|
||||
exit(1);
|
||||
}
|
||||
memcpy(n->buf, m->buf, n->size);
|
||||
}
|
||||
|
||||
if (m->tags != NULL) {
|
||||
n->tags = (unsigned char *)malloc(n->size);
|
||||
if (n->tags == NULL) {
|
||||
avrdude_message(MSG_INFO, "avr_dup_mem(): out of memory (memsize=%d)\n",
|
||||
n->size);
|
||||
exit(1);
|
||||
}
|
||||
memcpy(n->tags, m->tags, n->size);
|
||||
}
|
||||
|
||||
for (i = 0; i < AVR_OP_MAX; i++) {
|
||||
n->op[i] = avr_dup_opcode(n->op[i]);
|
||||
}
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
void avr_free_mem(AVRMEM * m)
|
||||
{
|
||||
int i;
|
||||
if (m->buf != NULL) {
|
||||
free(m->buf);
|
||||
m->buf = NULL;
|
||||
}
|
||||
if (m->tags != NULL) {
|
||||
free(m->tags);
|
||||
m->tags = NULL;
|
||||
}
|
||||
for(i=0;i<sizeof(m->op)/sizeof(m->op[0]);i++)
|
||||
{
|
||||
if (m->op[i] != NULL)
|
||||
{
|
||||
avr_free_opcode(m->op[i]);
|
||||
m->op[i] = NULL;
|
||||
}
|
||||
}
|
||||
free(m);
|
||||
}
|
||||
|
||||
AVRMEM * avr_locate_mem(AVRPART * p, char * desc)
|
||||
{
|
||||
AVRMEM * m, * match;
|
||||
LNODEID ln;
|
||||
int matches;
|
||||
int l;
|
||||
|
||||
l = strlen(desc);
|
||||
matches = 0;
|
||||
match = NULL;
|
||||
for (ln=lfirst(p->mem); ln; ln=lnext(ln)) {
|
||||
m = ldata(ln);
|
||||
if (strncmp(desc, m->desc, l) == 0) {
|
||||
match = m;
|
||||
matches++;
|
||||
}
|
||||
}
|
||||
|
||||
if (matches == 1)
|
||||
return match;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
void avr_mem_display(const char * prefix, FILE * f, AVRMEM * m, int type,
|
||||
int verbose)
|
||||
{
|
||||
int i, j;
|
||||
char * optr;
|
||||
|
||||
if (m == NULL) {
|
||||
fprintf(f,
|
||||
"%s Block Poll Page Polled\n"
|
||||
"%sMemory Type Mode Delay Size Indx Paged Size Size #Pages MinW MaxW ReadBack\n"
|
||||
"%s----------- ---- ----- ----- ---- ------ ------ ---- ------ ----- ----- ---------\n",
|
||||
prefix, prefix, prefix);
|
||||
}
|
||||
else {
|
||||
if (verbose > 2) {
|
||||
fprintf(f,
|
||||
"%s Block Poll Page Polled\n"
|
||||
"%sMemory Type Mode Delay Size Indx Paged Size Size #Pages MinW MaxW ReadBack\n"
|
||||
"%s----------- ---- ----- ----- ---- ------ ------ ---- ------ ----- ----- ---------\n",
|
||||
prefix, prefix, prefix);
|
||||
}
|
||||
fprintf(f,
|
||||
"%s%-11s %4d %5d %5d %4d %-6s %6d %4d %6d %5d %5d 0x%02x 0x%02x\n",
|
||||
prefix, m->desc, m->mode, m->delay, m->blocksize, m->pollindex,
|
||||
m->paged ? "yes" : "no",
|
||||
m->size,
|
||||
m->page_size,
|
||||
m->num_pages,
|
||||
m->min_write_delay,
|
||||
m->max_write_delay,
|
||||
m->readback[0],
|
||||
m->readback[1]);
|
||||
if (verbose > 4) {
|
||||
avrdude_message(MSG_TRACE2, "%s Memory Ops:\n"
|
||||
"%s Oeration Inst Bit Bit Type Bitno Value\n"
|
||||
"%s ----------- -------- -------- ----- -----\n",
|
||||
prefix, prefix, prefix);
|
||||
for (i=0; i<AVR_OP_MAX; i++) {
|
||||
if (m->op[i]) {
|
||||
for (j=31; j>=0; j--) {
|
||||
if (j==31)
|
||||
optr = avr_op_str(i);
|
||||
else
|
||||
optr = " ";
|
||||
fprintf(f,
|
||||
"%s %-11s %8d %8s %5d %5d\n",
|
||||
prefix, optr, j,
|
||||
bittype(m->op[i]->bit[j].type),
|
||||
m->op[i]->bit[j].bitno,
|
||||
m->op[i]->bit[j].value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Elementary functions dealing with AVRPART structures
|
||||
*/
|
||||
|
||||
|
||||
AVRPART * avr_new_part(void)
|
||||
{
|
||||
AVRPART * p;
|
||||
|
||||
p = (AVRPART *)malloc(sizeof(AVRPART));
|
||||
if (p == NULL) {
|
||||
avrdude_message(MSG_INFO, "new_part(): out of memory\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
memset(p, 0, sizeof(*p));
|
||||
|
||||
p->id[0] = 0;
|
||||
p->desc[0] = 0;
|
||||
p->reset_disposition = RESET_DEDICATED;
|
||||
p->retry_pulse = PIN_AVR_SCK;
|
||||
p->flags = AVRPART_SERIALOK | AVRPART_PARALLELOK | AVRPART_ENABLEPAGEPROGRAMMING;
|
||||
p->config_file[0] = 0;
|
||||
p->lineno = 0;
|
||||
memset(p->signature, 0xFF, 3);
|
||||
p->ctl_stack_type = CTL_STACK_NONE;
|
||||
p->ocdrev = -1;
|
||||
|
||||
p->mem = lcreat(NULL, 0);
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
|
||||
AVRPART * avr_dup_part(AVRPART * d)
|
||||
{
|
||||
AVRPART * p;
|
||||
LISTID save;
|
||||
LNODEID ln;
|
||||
int i;
|
||||
|
||||
p = avr_new_part();
|
||||
save = p->mem;
|
||||
|
||||
*p = *d;
|
||||
|
||||
p->mem = save;
|
||||
|
||||
for (ln=lfirst(d->mem); ln; ln=lnext(ln)) {
|
||||
ladd(p->mem, avr_dup_mem(ldata(ln)));
|
||||
}
|
||||
|
||||
for (i = 0; i < AVR_OP_MAX; i++) {
|
||||
p->op[i] = avr_dup_opcode(p->op[i]);
|
||||
}
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
void avr_free_part(AVRPART * d)
|
||||
{
|
||||
int i;
|
||||
ldestroy_cb(d->mem, (void(*)(void *))avr_free_mem);
|
||||
d->mem = NULL;
|
||||
for(i=0;i<sizeof(d->op)/sizeof(d->op[0]);i++)
|
||||
{
|
||||
if (d->op[i] != NULL)
|
||||
{
|
||||
avr_free_opcode(d->op[i]);
|
||||
d->op[i] = NULL;
|
||||
}
|
||||
}
|
||||
free(d);
|
||||
}
|
||||
|
||||
AVRPART * locate_part(LISTID parts, char * partdesc)
|
||||
{
|
||||
LNODEID ln1;
|
||||
AVRPART * p = NULL;
|
||||
int found;
|
||||
|
||||
found = 0;
|
||||
|
||||
for (ln1=lfirst(parts); ln1 && !found; ln1=lnext(ln1)) {
|
||||
p = ldata(ln1);
|
||||
if ((strcasecmp(partdesc, p->id) == 0) ||
|
||||
(strcasecmp(partdesc, p->desc) == 0))
|
||||
found = 1;
|
||||
}
|
||||
|
||||
if (found)
|
||||
return p;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
AVRPART * locate_part_by_avr910_devcode(LISTID parts, int devcode)
|
||||
{
|
||||
LNODEID ln1;
|
||||
AVRPART * p = NULL;
|
||||
|
||||
for (ln1=lfirst(parts); ln1; ln1=lnext(ln1)) {
|
||||
p = ldata(ln1);
|
||||
if (p->avr910_devcode == devcode)
|
||||
return p;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
AVRPART * locate_part_by_signature(LISTID parts, unsigned char * sig,
|
||||
int sigsize)
|
||||
{
|
||||
LNODEID ln1;
|
||||
AVRPART * p = NULL;
|
||||
int i;
|
||||
|
||||
if (sigsize == 3) {
|
||||
for (ln1=lfirst(parts); ln1; ln1=lnext(ln1)) {
|
||||
p = ldata(ln1);
|
||||
for (i=0; i<3; i++)
|
||||
if (p->signature[i] != sig[i])
|
||||
break;
|
||||
if (i == 3)
|
||||
return p;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Iterate over the list of avrparts given as "avrparts", and
|
||||
* call the callback function cb for each entry found. cb is being
|
||||
* passed the following arguments:
|
||||
* . the name of the avrpart (for -p)
|
||||
* . the descriptive text given in the config file
|
||||
* . the name of the config file this avrpart has been defined in
|
||||
* . the line number of the config file this avrpart has been defined at
|
||||
* . the "cookie" passed into walk_avrparts() (opaque client data)
|
||||
*/
|
||||
void walk_avrparts(LISTID avrparts, walk_avrparts_cb cb, void *cookie)
|
||||
{
|
||||
LNODEID ln1;
|
||||
AVRPART * p;
|
||||
|
||||
for (ln1 = lfirst(avrparts); ln1; ln1 = lnext(ln1)) {
|
||||
p = ldata(ln1);
|
||||
cb(p->id, p->desc, p->config_file, p->lineno, cookie);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Compare function to sort the list of programmers
|
||||
*/
|
||||
static int sort_avrparts_compare(AVRPART * p1,AVRPART * p2)
|
||||
{
|
||||
if(p1 == NULL || p2 == NULL) {
|
||||
return 0;
|
||||
}
|
||||
return strncasecmp(p1->desc,p2->desc,AVR_DESCLEN);
|
||||
}
|
||||
|
||||
/*
|
||||
* Sort the list of programmers given as "programmers"
|
||||
*/
|
||||
void sort_avrparts(LISTID avrparts)
|
||||
{
|
||||
lsort(avrparts,(int (*)(void*, void*)) sort_avrparts_compare);
|
||||
}
|
||||
|
||||
|
||||
static char * reset_disp_str(int r)
|
||||
{
|
||||
switch (r) {
|
||||
case RESET_DEDICATED : return "dedicated";
|
||||
case RESET_IO : return "possible i/o";
|
||||
default : return "<invalid>";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void avr_display(FILE * f, AVRPART * p, const char * prefix, int verbose)
|
||||
{
|
||||
int i;
|
||||
char * buf;
|
||||
const char * px;
|
||||
LNODEID ln;
|
||||
AVRMEM * m;
|
||||
|
||||
fprintf(f,
|
||||
"%sAVR Part : %s\n"
|
||||
"%sChip Erase delay : %d us\n"
|
||||
"%sPAGEL : P%02X\n"
|
||||
"%sBS2 : P%02X\n"
|
||||
"%sRESET disposition : %s\n"
|
||||
"%sRETRY pulse : %s\n"
|
||||
"%sserial program mode : %s\n"
|
||||
"%sparallel program mode : %s\n"
|
||||
"%sTimeout : %d\n"
|
||||
"%sStabDelay : %d\n"
|
||||
"%sCmdexeDelay : %d\n"
|
||||
"%sSyncLoops : %d\n"
|
||||
"%sByteDelay : %d\n"
|
||||
"%sPollIndex : %d\n"
|
||||
"%sPollValue : 0x%02x\n"
|
||||
"%sMemory Detail :\n\n",
|
||||
prefix, p->desc,
|
||||
prefix, p->chip_erase_delay,
|
||||
prefix, p->pagel,
|
||||
prefix, p->bs2,
|
||||
prefix, reset_disp_str(p->reset_disposition),
|
||||
prefix, avr_pin_name(p->retry_pulse),
|
||||
prefix, (p->flags & AVRPART_SERIALOK) ? "yes" : "no",
|
||||
prefix, (p->flags & AVRPART_PARALLELOK) ?
|
||||
((p->flags & AVRPART_PSEUDOPARALLEL) ? "pseudo" : "yes") : "no",
|
||||
prefix, p->timeout,
|
||||
prefix, p->stabdelay,
|
||||
prefix, p->cmdexedelay,
|
||||
prefix, p->synchloops,
|
||||
prefix, p->bytedelay,
|
||||
prefix, p->pollindex,
|
||||
prefix, p->pollvalue,
|
||||
prefix);
|
||||
|
||||
px = prefix;
|
||||
i = strlen(prefix) + 5;
|
||||
buf = (char *)malloc(i);
|
||||
if (buf == NULL) {
|
||||
/* ugh, this is not important enough to bail, just ignore it */
|
||||
}
|
||||
else {
|
||||
strcpy(buf, prefix);
|
||||
strcat(buf, " ");
|
||||
px = buf;
|
||||
}
|
||||
|
||||
if (verbose <= 2) {
|
||||
avr_mem_display(px, f, NULL, 0, verbose);
|
||||
}
|
||||
for (ln=lfirst(p->mem); ln; ln=lnext(ln)) {
|
||||
m = ldata(ln);
|
||||
avr_mem_display(px, f, m, i, verbose);
|
||||
}
|
||||
|
||||
if (buf)
|
||||
free(buf);
|
||||
}
|
||||
658
src/bitbang.c
Normal file
658
src/bitbang.c
Normal file
@@ -0,0 +1,658 @@
|
||||
/*
|
||||
* avrdude - A Downloader/Uploader for AVR device programmers
|
||||
* Copyright (C) 2000, 2001, 2002, 2003 Brian S. Dean <bsd@bsdhome.com>
|
||||
* Copyright (C) 2005 Juliane Holzt <avrdude@juliane.holzt.de>
|
||||
* Copyright (C) 2011 Darell Tan <darell.tan@gmail.com>
|
||||
*
|
||||
* 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
/* $Id$ */
|
||||
|
||||
#include "ac_cfg.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
|
||||
#if !defined(WIN32NATIVE)
|
||||
# include <signal.h>
|
||||
# include <sys/time.h>
|
||||
#endif
|
||||
|
||||
#include "avrdude.h"
|
||||
#include "libavrdude.h"
|
||||
|
||||
#include "par.h"
|
||||
#include "serbb.h"
|
||||
#include "tpi.h"
|
||||
#include "bitbang.h"
|
||||
|
||||
static int delay_decrement;
|
||||
|
||||
#if defined(WIN32NATIVE)
|
||||
static int has_perfcount;
|
||||
static LARGE_INTEGER freq;
|
||||
#else
|
||||
static volatile int done;
|
||||
|
||||
typedef void (*mysighandler_t)(int);
|
||||
static mysighandler_t saved_alarmhandler;
|
||||
|
||||
static void alarmhandler(int signo)
|
||||
{
|
||||
done = 1;
|
||||
signal(SIGALRM, saved_alarmhandler);
|
||||
}
|
||||
#endif /* WIN32NATIVE */
|
||||
|
||||
/*
|
||||
* Calibrate the microsecond delay loop below.
|
||||
*/
|
||||
static void bitbang_calibrate_delay(void)
|
||||
{
|
||||
#if defined(WIN32NATIVE)
|
||||
/*
|
||||
* If the hardware supports a high-resolution performance counter,
|
||||
* we ultimately prefer that one, as it gives quite accurate delays
|
||||
* on modern high-speed CPUs.
|
||||
*/
|
||||
if (QueryPerformanceFrequency(&freq))
|
||||
{
|
||||
has_perfcount = 1;
|
||||
avrdude_message(MSG_NOTICE2, "%s: Using performance counter for bitbang delays\n",
|
||||
progname);
|
||||
}
|
||||
else
|
||||
{
|
||||
/*
|
||||
* If a high-resolution performance counter is not available, we
|
||||
* don't have any Win32 implementation for setting up the
|
||||
* per-microsecond delay count, so we can only run on a
|
||||
* preconfigured delay stepping there. The figure below should at
|
||||
* least be correct within an order of magnitude, judging from the
|
||||
* auto-calibration figures seen on various Unix systems on
|
||||
* comparable hardware.
|
||||
*/
|
||||
avrdude_message(MSG_NOTICE2, "%s: Using guessed per-microsecond delay count for bitbang delays\n",
|
||||
progname);
|
||||
delay_decrement = 100;
|
||||
}
|
||||
#else /* !WIN32NATIVE */
|
||||
struct itimerval itv;
|
||||
volatile int i;
|
||||
|
||||
avrdude_message(MSG_NOTICE2, "%s: Calibrating delay loop...",
|
||||
progname);
|
||||
i = 0;
|
||||
done = 0;
|
||||
saved_alarmhandler = signal(SIGALRM, alarmhandler);
|
||||
/*
|
||||
* Set ITIMER_REAL to 100 ms. All known systems have a timer
|
||||
* granularity of 10 ms or better, so counting the delay cycles
|
||||
* accumulating over 100 ms should give us a rather realistic
|
||||
* picture, without annoying the user by a lengthy startup time (as
|
||||
* an alarm(1) would do). Of course, if heavy system activity
|
||||
* happens just during calibration but stops before the remaining
|
||||
* part of AVRDUDE runs, this will yield wrong values. There's not
|
||||
* much we can do about this.
|
||||
*/
|
||||
itv.it_value.tv_sec = 0;
|
||||
itv.it_value.tv_usec = 100000;
|
||||
itv.it_interval.tv_sec = itv.it_interval.tv_usec = 0;
|
||||
setitimer(ITIMER_REAL, &itv, 0);
|
||||
while (!done)
|
||||
i--;
|
||||
itv.it_value.tv_sec = itv.it_value.tv_usec = 0;
|
||||
setitimer(ITIMER_REAL, &itv, 0);
|
||||
/*
|
||||
* Calculate back from 100 ms to 1 us.
|
||||
*/
|
||||
delay_decrement = -i / 100000;
|
||||
avrdude_message(MSG_NOTICE2, " calibrated to %d cycles per us\n",
|
||||
delay_decrement);
|
||||
#endif /* WIN32NATIVE */
|
||||
}
|
||||
|
||||
/*
|
||||
* Delay for approximately the number of microseconds specified.
|
||||
* usleep()'s granularity is usually like 1 ms or 10 ms, so it's not
|
||||
* really suitable for short delays in bit-bang algorithms.
|
||||
*/
|
||||
void bitbang_delay(unsigned int us)
|
||||
{
|
||||
#if defined(WIN32NATIVE)
|
||||
LARGE_INTEGER countNow, countEnd;
|
||||
|
||||
if (has_perfcount)
|
||||
{
|
||||
QueryPerformanceCounter(&countNow);
|
||||
countEnd.QuadPart = countNow.QuadPart + freq.QuadPart * us / 1000000ll;
|
||||
|
||||
while (countNow.QuadPart < countEnd.QuadPart)
|
||||
QueryPerformanceCounter(&countNow);
|
||||
}
|
||||
else /* no performance counters -- run normal uncalibrated delay */
|
||||
{
|
||||
#endif /* WIN32NATIVE */
|
||||
volatile unsigned int del = us * delay_decrement;
|
||||
|
||||
while (del > 0)
|
||||
del--;
|
||||
#if defined(WIN32NATIVE)
|
||||
}
|
||||
#endif /* WIN32NATIVE */
|
||||
}
|
||||
|
||||
/*
|
||||
* transmit and receive a byte of data to/from the AVR device
|
||||
*/
|
||||
static unsigned char bitbang_txrx(PROGRAMMER * pgm, unsigned char byte)
|
||||
{
|
||||
int i;
|
||||
unsigned char r, b, rbyte;
|
||||
|
||||
rbyte = 0;
|
||||
for (i=7; i>=0; i--) {
|
||||
/*
|
||||
* Write and read one bit on SPI.
|
||||
* Some notes on timing: Let T be the time it takes to do
|
||||
* one pgm->setpin()-call resp. par clrpin()-call, then
|
||||
* - SCK is high for 2T
|
||||
* - SCK is low for 2T
|
||||
* - MOSI setuptime is 1T
|
||||
* - MOSI holdtime is 3T
|
||||
* - SCK low to MISO read is 2T to 3T
|
||||
* So we are within programming specs (expect for AT90S1200),
|
||||
* if and only if T>t_CLCL (t_CLCL=clock period of target system).
|
||||
*
|
||||
* Due to the delay introduced by "IN" and "OUT"-commands,
|
||||
* T is greater than 1us (more like 2us) on x86-architectures.
|
||||
* So programming works safely down to 1MHz target clock.
|
||||
*/
|
||||
|
||||
b = (byte >> i) & 0x01;
|
||||
|
||||
/* set the data input line as desired */
|
||||
pgm->setpin(pgm, PIN_AVR_MOSI, b);
|
||||
|
||||
pgm->setpin(pgm, PIN_AVR_SCK, 1);
|
||||
|
||||
/*
|
||||
* read the result bit (it is either valid from a previous falling
|
||||
* edge or it is ignored in the current context)
|
||||
*/
|
||||
r = pgm->getpin(pgm, PIN_AVR_MISO);
|
||||
|
||||
pgm->setpin(pgm, PIN_AVR_SCK, 0);
|
||||
|
||||
rbyte |= r << i;
|
||||
}
|
||||
|
||||
return rbyte;
|
||||
}
|
||||
|
||||
static int bitbang_tpi_clk(PROGRAMMER * pgm)
|
||||
{
|
||||
unsigned char r = 0;
|
||||
pgm->setpin(pgm, PIN_AVR_SCK, 1);
|
||||
|
||||
r = pgm->getpin(pgm, PIN_AVR_MISO);
|
||||
|
||||
pgm->setpin(pgm, PIN_AVR_SCK, 0);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
void bitbang_tpi_tx(PROGRAMMER * pgm, unsigned char byte)
|
||||
{
|
||||
int i;
|
||||
unsigned char b, parity;
|
||||
|
||||
/* start bit */
|
||||
pgm->setpin(pgm, PIN_AVR_MOSI, 0);
|
||||
bitbang_tpi_clk(pgm);
|
||||
|
||||
parity = 0;
|
||||
for (i = 0; i <= 7; i++) {
|
||||
b = (byte >> i) & 0x01;
|
||||
parity ^= b;
|
||||
|
||||
/* set the data input line as desired */
|
||||
pgm->setpin(pgm, PIN_AVR_MOSI, b);
|
||||
bitbang_tpi_clk(pgm);
|
||||
}
|
||||
|
||||
/* parity bit */
|
||||
pgm->setpin(pgm, PIN_AVR_MOSI, parity);
|
||||
bitbang_tpi_clk(pgm);
|
||||
|
||||
/* 2 stop bits */
|
||||
pgm->setpin(pgm, PIN_AVR_MOSI, 1);
|
||||
bitbang_tpi_clk(pgm);
|
||||
bitbang_tpi_clk(pgm);
|
||||
}
|
||||
|
||||
int bitbang_tpi_rx(PROGRAMMER * pgm)
|
||||
{
|
||||
int i;
|
||||
unsigned char b, rbyte, parity;
|
||||
|
||||
/* make sure pin is on for "pullup" */
|
||||
pgm->setpin(pgm, PIN_AVR_MOSI, 1);
|
||||
|
||||
/* wait for start bit (up to 10 bits) */
|
||||
b = 1;
|
||||
for (i = 0; i < 10; i++) {
|
||||
b = bitbang_tpi_clk(pgm);
|
||||
if (b == 0)
|
||||
break;
|
||||
}
|
||||
if (b != 0) {
|
||||
avrdude_message(MSG_INFO, "bitbang_tpi_rx: start bit not received correctly\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
rbyte = 0;
|
||||
parity = 0;
|
||||
for (i=0; i<=7; i++) {
|
||||
b = bitbang_tpi_clk(pgm);
|
||||
parity ^= b;
|
||||
|
||||
rbyte |= b << i;
|
||||
}
|
||||
|
||||
/* parity bit */
|
||||
if (bitbang_tpi_clk(pgm) != parity) {
|
||||
avrdude_message(MSG_INFO, "bitbang_tpi_rx: parity bit is wrong\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* 2 stop bits */
|
||||
b = 1;
|
||||
b &= bitbang_tpi_clk(pgm);
|
||||
b &= bitbang_tpi_clk(pgm);
|
||||
if (b != 1) {
|
||||
avrdude_message(MSG_INFO, "bitbang_tpi_rx: stop bits not received correctly\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return rbyte;
|
||||
}
|
||||
|
||||
int bitbang_rdy_led(PROGRAMMER * pgm, int value)
|
||||
{
|
||||
pgm->setpin(pgm, PIN_LED_RDY, !value);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int bitbang_err_led(PROGRAMMER * pgm, int value)
|
||||
{
|
||||
pgm->setpin(pgm, PIN_LED_ERR, !value);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int bitbang_pgm_led(PROGRAMMER * pgm, int value)
|
||||
{
|
||||
pgm->setpin(pgm, PIN_LED_PGM, !value);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int bitbang_vfy_led(PROGRAMMER * pgm, int value)
|
||||
{
|
||||
pgm->setpin(pgm, PIN_LED_VFY, !value);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* transmit an AVR device command and return the results; 'cmd' and
|
||||
* 'res' must point to at least a 4 byte data buffer
|
||||
*/
|
||||
int bitbang_cmd(PROGRAMMER * pgm, const unsigned char *cmd,
|
||||
unsigned char *res)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i=0; i<4; i++) {
|
||||
res[i] = bitbang_txrx(pgm, cmd[i]);
|
||||
}
|
||||
|
||||
if(verbose >= 2)
|
||||
{
|
||||
avrdude_message(MSG_NOTICE2, "bitbang_cmd(): [ ");
|
||||
for(i = 0; i < 4; i++)
|
||||
avrdude_message(MSG_NOTICE2, "%02X ", cmd[i]);
|
||||
avrdude_message(MSG_NOTICE2, "] [ ");
|
||||
for(i = 0; i < 4; i++)
|
||||
{
|
||||
avrdude_message(MSG_NOTICE2, "%02X ", res[i]);
|
||||
}
|
||||
avrdude_message(MSG_NOTICE2, "]\n");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int bitbang_cmd_tpi(PROGRAMMER * pgm, const unsigned char *cmd,
|
||||
int cmd_len, unsigned char *res, int res_len)
|
||||
{
|
||||
int i, r;
|
||||
|
||||
pgm->pgm_led(pgm, ON);
|
||||
|
||||
for (i=0; i<cmd_len; i++) {
|
||||
bitbang_tpi_tx(pgm, cmd[i]);
|
||||
}
|
||||
|
||||
r = 0;
|
||||
for (i=0; i<res_len; i++) {
|
||||
r = bitbang_tpi_rx(pgm);
|
||||
if (r == -1)
|
||||
break;
|
||||
res[i] = r;
|
||||
}
|
||||
|
||||
if(verbose >= 2)
|
||||
{
|
||||
avrdude_message(MSG_NOTICE2, "bitbang_cmd_tpi(): [ ");
|
||||
for(i = 0; i < cmd_len; i++)
|
||||
avrdude_message(MSG_NOTICE2, "%02X ", cmd[i]);
|
||||
avrdude_message(MSG_NOTICE2, "] [ ");
|
||||
for(i = 0; i < res_len; i++)
|
||||
{
|
||||
avrdude_message(MSG_NOTICE2, "%02X ", res[i]);
|
||||
}
|
||||
avrdude_message(MSG_NOTICE2, "]\n");
|
||||
}
|
||||
|
||||
pgm->pgm_led(pgm, OFF);
|
||||
if (r == -1)
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* transmit bytes via SPI and return the results; 'cmd' and
|
||||
* 'res' must point to data buffers
|
||||
*/
|
||||
int bitbang_spi(PROGRAMMER * pgm, const unsigned char *cmd,
|
||||
unsigned char *res, int count)
|
||||
{
|
||||
int i;
|
||||
|
||||
pgm->setpin(pgm, PIN_LED_PGM, 0);
|
||||
|
||||
for (i=0; i<count; i++) {
|
||||
res[i] = bitbang_txrx(pgm, cmd[i]);
|
||||
}
|
||||
|
||||
pgm->setpin(pgm, PIN_LED_PGM, 1);
|
||||
|
||||
if(verbose >= 2)
|
||||
{
|
||||
avrdude_message(MSG_NOTICE2, "bitbang_cmd(): [ ");
|
||||
for(i = 0; i < count; i++)
|
||||
avrdude_message(MSG_NOTICE2, "%02X ", cmd[i]);
|
||||
avrdude_message(MSG_NOTICE2, "] [ ");
|
||||
for(i = 0; i < count; i++)
|
||||
{
|
||||
avrdude_message(MSG_NOTICE2, "%02X ", res[i]);
|
||||
}
|
||||
avrdude_message(MSG_NOTICE2, "]\n");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* issue the 'chip erase' command to the AVR device
|
||||
*/
|
||||
int bitbang_chip_erase(PROGRAMMER * pgm, AVRPART * p)
|
||||
{
|
||||
unsigned char cmd[4];
|
||||
unsigned char res[4];
|
||||
AVRMEM *mem;
|
||||
|
||||
if (p->flags & AVRPART_HAS_TPI) {
|
||||
pgm->pgm_led(pgm, ON);
|
||||
|
||||
while (avr_tpi_poll_nvmbsy(pgm));
|
||||
|
||||
/* NVMCMD <- CHIP_ERASE */
|
||||
bitbang_tpi_tx(pgm, TPI_CMD_SOUT | TPI_SIO_ADDR(TPI_IOREG_NVMCMD));
|
||||
bitbang_tpi_tx(pgm, TPI_NVMCMD_CHIP_ERASE); /* CHIP_ERASE */
|
||||
|
||||
/* Set Pointer Register */
|
||||
mem = avr_locate_mem(p, "flash");
|
||||
if (mem == NULL) {
|
||||
avrdude_message(MSG_INFO, "No flash memory to erase for part %s\n",
|
||||
p->desc);
|
||||
return -1;
|
||||
}
|
||||
bitbang_tpi_tx(pgm, TPI_CMD_SSTPR | 0);
|
||||
bitbang_tpi_tx(pgm, (mem->offset & 0xFF) | 1); /* high byte */
|
||||
bitbang_tpi_tx(pgm, TPI_CMD_SSTPR | 1);
|
||||
bitbang_tpi_tx(pgm, (mem->offset >> 8) & 0xFF);
|
||||
|
||||
/* write dummy value to start erase */
|
||||
bitbang_tpi_tx(pgm, TPI_CMD_SST);
|
||||
bitbang_tpi_tx(pgm, 0xFF);
|
||||
|
||||
while (avr_tpi_poll_nvmbsy(pgm));
|
||||
|
||||
pgm->pgm_led(pgm, OFF);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (p->op[AVR_OP_CHIP_ERASE] == NULL) {
|
||||
avrdude_message(MSG_INFO, "chip erase instruction not defined for part \"%s\"\n",
|
||||
p->desc);
|
||||
return -1;
|
||||
}
|
||||
|
||||
pgm->pgm_led(pgm, ON);
|
||||
|
||||
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);
|
||||
|
||||
pgm->pgm_led(pgm, OFF);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* issue the 'program enable' command to the AVR device
|
||||
*/
|
||||
int bitbang_program_enable(PROGRAMMER * pgm, AVRPART * p)
|
||||
{
|
||||
unsigned char cmd[4];
|
||||
unsigned char res[4];
|
||||
int i;
|
||||
|
||||
if (p->flags & AVRPART_HAS_TPI) {
|
||||
/* enable NVM programming */
|
||||
bitbang_tpi_tx(pgm, TPI_CMD_SKEY);
|
||||
for (i = sizeof(tpi_skey) - 1; i >= 0; i--)
|
||||
bitbang_tpi_tx(pgm, tpi_skey[i]);
|
||||
|
||||
/* check NVMEN bit */
|
||||
bitbang_tpi_tx(pgm, TPI_CMD_SLDCS | TPI_REG_TPISR);
|
||||
i = bitbang_tpi_rx(pgm);
|
||||
return (i != -1 && (i & TPI_REG_TPISR_NVMEN)) ? 0 : -2;
|
||||
}
|
||||
|
||||
if (p->op[AVR_OP_PGM_ENABLE] == NULL) {
|
||||
avrdude_message(MSG_INFO, "program enable instruction not defined for part \"%s\"\n",
|
||||
p->desc);
|
||||
return -1;
|
||||
}
|
||||
|
||||
memset(cmd, 0, sizeof(cmd));
|
||||
avr_set_bits(p->op[AVR_OP_PGM_ENABLE], cmd);
|
||||
pgm->cmd(pgm, cmd, res);
|
||||
|
||||
if (res[2] != cmd[1])
|
||||
return -2;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* initialize the AVR device and prepare it to accept commands
|
||||
*/
|
||||
int bitbang_initialize(PROGRAMMER * pgm, AVRPART * p)
|
||||
{
|
||||
int rc;
|
||||
int tries;
|
||||
int i;
|
||||
|
||||
bitbang_calibrate_delay();
|
||||
|
||||
pgm->powerup(pgm);
|
||||
usleep(20000);
|
||||
|
||||
/* TPIDATA is a single line, so MISO & MOSI should be connected */
|
||||
if (p->flags & AVRPART_HAS_TPI) {
|
||||
/* make sure cmd_tpi() is defined */
|
||||
if (pgm->cmd_tpi == NULL) {
|
||||
avrdude_message(MSG_INFO, "%s: Error: %s programmer does not support TPI\n",
|
||||
progname, pgm->type);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* bring RESET high first */
|
||||
pgm->setpin(pgm, PIN_AVR_RESET, 1);
|
||||
usleep(128000); /* wait t_TOUT (32-128ms) */
|
||||
|
||||
/* RESET must be LOW in case the existing code is driving the TPI pins: */
|
||||
pgm->setpin(pgm, PIN_AVR_RESET, 0);
|
||||
|
||||
avrdude_message(MSG_NOTICE2, "doing MOSI-MISO link check\n");
|
||||
|
||||
pgm->setpin(pgm, PIN_AVR_MOSI, 0);
|
||||
if (pgm->getpin(pgm, PIN_AVR_MISO) != 0) {
|
||||
avrdude_message(MSG_INFO, "MOSI->MISO 0 failed\n");
|
||||
return -1;
|
||||
}
|
||||
pgm->setpin(pgm, PIN_AVR_MOSI, 1);
|
||||
if (pgm->getpin(pgm, PIN_AVR_MISO) != 1) {
|
||||
avrdude_message(MSG_INFO, "MOSI->MISO 1 failed\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
avrdude_message(MSG_NOTICE2, "MOSI-MISO link present\n");
|
||||
}
|
||||
|
||||
pgm->setpin(pgm, PIN_AVR_SCK, 0);
|
||||
pgm->setpin(pgm, PIN_AVR_RESET, 0);
|
||||
usleep(20000);
|
||||
|
||||
if (p->flags & AVRPART_HAS_TPI) {
|
||||
/* keep TPIDATA high for 16 clock cycles */
|
||||
pgm->setpin(pgm, PIN_AVR_MOSI, 1);
|
||||
for (i = 0; i < 16; i++)
|
||||
pgm->highpulsepin(pgm, PIN_AVR_SCK);
|
||||
|
||||
/* remove extra guard timing bits */
|
||||
bitbang_tpi_tx(pgm, TPI_CMD_SSTCS | TPI_REG_TPIPCR);
|
||||
bitbang_tpi_tx(pgm, 0x7);
|
||||
|
||||
/* read TPI ident reg */
|
||||
bitbang_tpi_tx(pgm, TPI_CMD_SLDCS | TPI_REG_TPIIR);
|
||||
rc = bitbang_tpi_rx(pgm);
|
||||
if (rc != 0x80) {
|
||||
avrdude_message(MSG_INFO, "TPIIR not correct\n");
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
pgm->highpulsepin(pgm, PIN_AVR_RESET);
|
||||
}
|
||||
|
||||
usleep(20000); /* 20 ms XXX should be a per-chip parameter */
|
||||
|
||||
/*
|
||||
* Enable programming mode. If we are programming an AT90S1200, we
|
||||
* can only issue the command and hope it worked. If we are using
|
||||
* one of the other chips, the chip will echo 0x53 when issuing the
|
||||
* third byte of the command. In this case, try up to 32 times in
|
||||
* order to possibly get back into sync with the chip if we are out
|
||||
* of sync.
|
||||
*/
|
||||
if (p->flags & AVRPART_IS_AT90S1200) {
|
||||
pgm->program_enable(pgm, p);
|
||||
}
|
||||
else {
|
||||
tries = 0;
|
||||
do {
|
||||
rc = pgm->program_enable(pgm, p);
|
||||
if ((rc == 0)||(rc == -1))
|
||||
break;
|
||||
pgm->highpulsepin(pgm, p->retry_pulse/*PIN_AVR_SCK*/);
|
||||
tries++;
|
||||
} while (tries < 65);
|
||||
|
||||
/*
|
||||
* can't sync with the device, maybe it's not attached?
|
||||
*/
|
||||
if (rc) {
|
||||
avrdude_message(MSG_INFO, "%s: AVR device not responding\n", progname);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int verify_pin_assigned(PROGRAMMER * pgm, int pin, char * desc)
|
||||
{
|
||||
if (pgm->pinno[pin] == 0) {
|
||||
avrdude_message(MSG_INFO, "%s: error: no pin has been assigned for %s\n",
|
||||
progname, desc);
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Verify all prerequisites for a bit-bang programmer are present.
|
||||
*/
|
||||
int bitbang_check_prerequisites(PROGRAMMER *pgm)
|
||||
{
|
||||
|
||||
if (verify_pin_assigned(pgm, PIN_AVR_RESET, "AVR RESET") < 0)
|
||||
return -1;
|
||||
if (verify_pin_assigned(pgm, PIN_AVR_SCK, "AVR SCK") < 0)
|
||||
return -1;
|
||||
if (verify_pin_assigned(pgm, PIN_AVR_MISO, "AVR MISO") < 0)
|
||||
return -1;
|
||||
if (verify_pin_assigned(pgm, PIN_AVR_MOSI, "AVR MOSI") < 0)
|
||||
return -1;
|
||||
|
||||
if (pgm->cmd == NULL) {
|
||||
avrdude_message(MSG_INFO, "%s: error: no cmd() method defined for bitbang programmer\n",
|
||||
progname);
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
58
src/bitbang.h
Normal file
58
src/bitbang.h
Normal file
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
* avrdude - A Downloader/Uploader for AVR device programmers
|
||||
* Copyright (C) 2000, 2001, 2002, 2003 Brian S. Dean <bsd@bsdhome.com>
|
||||
* Copyright (C) 2005 Juliane Holzt <avrdude@juliane.holzt.de>
|
||||
* Copyright (C) 2011 Darell Tan <darell.tan@gmail.com>
|
||||
*
|
||||
* 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
/* $Id$ */
|
||||
|
||||
#ifndef bitbang_h
|
||||
#define bitbang_h
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
int bitbang_setpin(int fd, int pin, int value);
|
||||
int bitbang_getpin(int fd, int pin);
|
||||
int bitbang_highpulsepin(int fd, int pin);
|
||||
void bitbang_delay(unsigned int us);
|
||||
|
||||
int bitbang_check_prerequisites(PROGRAMMER *pgm);
|
||||
|
||||
int bitbang_rdy_led (PROGRAMMER * pgm, int value);
|
||||
int bitbang_err_led (PROGRAMMER * pgm, int value);
|
||||
int bitbang_pgm_led (PROGRAMMER * pgm, int value);
|
||||
int bitbang_vfy_led (PROGRAMMER * pgm, int value);
|
||||
int bitbang_cmd (PROGRAMMER * pgm, const unsigned char *cmd,
|
||||
unsigned char *res);
|
||||
int bitbang_cmd_tpi (PROGRAMMER * pgm, const unsigned char *cmd,
|
||||
int cmd_len, unsigned char *res, int res_len);
|
||||
int bitbang_spi (PROGRAMMER * pgm, const unsigned char *cmd,
|
||||
unsigned char *res, int count);
|
||||
int bitbang_chip_erase (PROGRAMMER * pgm, AVRPART * p);
|
||||
int bitbang_program_enable (PROGRAMMER * pgm, AVRPART * p);
|
||||
void bitbang_powerup (PROGRAMMER * pgm);
|
||||
void bitbang_powerdown (PROGRAMMER * pgm);
|
||||
int bitbang_initialize (PROGRAMMER * pgm, AVRPART * p);
|
||||
void bitbang_disable (PROGRAMMER * pgm);
|
||||
void bitbang_enable (PROGRAMMER * pgm);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
25
src/bootstrap
Executable file
25
src/bootstrap
Executable file
@@ -0,0 +1,25 @@
|
||||
#! /bin/sh
|
||||
|
||||
: ${AUTOHEADER="autoheader${AC_VER}"}
|
||||
: ${AUTOCONF="autoconf${AC_VER}"}
|
||||
: ${ACLOCAL="aclocal${AM_VER}"}
|
||||
: ${AUTOMAKE="automake${AM_VER}"}
|
||||
|
||||
export ACLOCAL AUTOHEADER AUTOCONF AUTOMAKE
|
||||
|
||||
# Bootstrap the build system.
|
||||
|
||||
set -x
|
||||
|
||||
rm -rf autom4te.cache
|
||||
|
||||
# MacOS calls it "glibtoolize", everyone else "libtoolize"
|
||||
# probe for that
|
||||
LIBTOOLIZE=libtoolize
|
||||
glibtoolize --version > /dev/null 2>&1 && LIBTOOLIZE=glibtoolize
|
||||
${LIBTOOLIZE}
|
||||
|
||||
${ACLOCAL}
|
||||
${AUTOHEADER}
|
||||
${AUTOCONF}
|
||||
${AUTOMAKE} -a -c
|
||||
1371
src/buspirate.c
Normal file
1371
src/buspirate.c
Normal file
File diff suppressed because it is too large
Load Diff
32
src/buspirate.h
Normal file
32
src/buspirate.h
Normal file
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* avrdude - A Downloader/Uploader for AVR device programmers
|
||||
*
|
||||
* avrdude support for The Bus Pirate - universal serial interface
|
||||
*
|
||||
* Copyright (C) 2009 Michal Ludvig <mludvig@logix.net.nz>
|
||||
*
|
||||
* 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/* $Id$ */
|
||||
|
||||
#ifndef buspirate_h
|
||||
#define buspirate_h
|
||||
|
||||
extern const char buspirate_desc[];
|
||||
extern const char buspirate_bb_desc[];
|
||||
void buspirate_initpgm (struct programmer_t *pgm);
|
||||
void buspirate_bb_initpgm (struct programmer_t *pgm);
|
||||
|
||||
#endif
|
||||
763
src/butterfly.c
Normal file
763
src/butterfly.c
Normal file
@@ -0,0 +1,763 @@
|
||||
/*
|
||||
* avrdude - A Downloader/Uploader for AVR device programmers
|
||||
* Copyright (C) 2003-2004 Theodore A. Roth <troth@openavr.org>
|
||||
* Copyright (C) 2005, 2007 Joerg Wunsch <j@uriah.heep.sax.de>
|
||||
*
|
||||
* 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/* $Id$ */
|
||||
|
||||
/*
|
||||
* avrdude interface for the serial programming mode of the Atmel butterfly
|
||||
* evaluation board. This board features a bootloader which uses a protocol
|
||||
* very similar, but not identical, to the one described in application note
|
||||
* avr910.
|
||||
*
|
||||
* Actually, the butterfly uses a predecessor of the avr910 protocol
|
||||
* which is described in application notes avr109 (generic AVR
|
||||
* bootloader) and avr911 (opensource programmer). This file now
|
||||
* fully handles the features present in avr109. It should probably
|
||||
* be renamed to avr109, but we rather stick with the old name inside
|
||||
* the file. We'll provide aliases for "avr109" and "avr911" in
|
||||
* avrdude.conf so users could call it by these name as well.
|
||||
*/
|
||||
|
||||
|
||||
#include "ac_cfg.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <ctype.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "avrdude.h"
|
||||
#include "libavrdude.h"
|
||||
|
||||
#include "butterfly.h"
|
||||
|
||||
/*
|
||||
* Private data for this programmer.
|
||||
*/
|
||||
struct pdata
|
||||
{
|
||||
char has_auto_incr_addr;
|
||||
unsigned int buffersize;
|
||||
};
|
||||
|
||||
#define PDATA(pgm) ((struct pdata *)(pgm->cookie))
|
||||
|
||||
static void butterfly_setup(PROGRAMMER * pgm)
|
||||
{
|
||||
if ((pgm->cookie = malloc(sizeof(struct pdata))) == 0) {
|
||||
avrdude_message(MSG_INFO, "%s: butterfly_setup(): Out of memory allocating private data\n",
|
||||
progname);
|
||||
exit(1);
|
||||
}
|
||||
memset(pgm->cookie, 0, sizeof(struct pdata));
|
||||
}
|
||||
|
||||
static void butterfly_teardown(PROGRAMMER * pgm)
|
||||
{
|
||||
free(pgm->cookie);
|
||||
}
|
||||
|
||||
static int butterfly_send(PROGRAMMER * pgm, char * buf, size_t len)
|
||||
{
|
||||
return serial_send(&pgm->fd, (unsigned char *)buf, len);
|
||||
}
|
||||
|
||||
|
||||
static int butterfly_recv(PROGRAMMER * pgm, char * buf, size_t len)
|
||||
{
|
||||
int rv;
|
||||
|
||||
rv = serial_recv(&pgm->fd, (unsigned char *)buf, len);
|
||||
if (rv < 0) {
|
||||
avrdude_message(MSG_INFO, "%s: butterfly_recv(): programmer is not responding\n",
|
||||
progname);
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int butterfly_drain(PROGRAMMER * pgm, int display)
|
||||
{
|
||||
return serial_drain(&pgm->fd, display);
|
||||
}
|
||||
|
||||
|
||||
static int butterfly_vfy_cmd_sent(PROGRAMMER * pgm, char * errmsg)
|
||||
{
|
||||
char c;
|
||||
|
||||
butterfly_recv(pgm, &c, 1);
|
||||
if (c != '\r') {
|
||||
avrdude_message(MSG_INFO, "%s: error: programmer did not respond to command: %s\n",
|
||||
progname, errmsg);
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int butterfly_rdy_led(PROGRAMMER * pgm, int value)
|
||||
{
|
||||
/* Do nothing. */
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int butterfly_err_led(PROGRAMMER * pgm, int value)
|
||||
{
|
||||
/* Do nothing. */
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int butterfly_pgm_led(PROGRAMMER * pgm, int value)
|
||||
{
|
||||
/* Do nothing. */
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int butterfly_vfy_led(PROGRAMMER * pgm, int value)
|
||||
{
|
||||
/* Do nothing. */
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* issue the 'chip erase' command to the butterfly board
|
||||
*/
|
||||
static int butterfly_chip_erase(PROGRAMMER * pgm, AVRPART * p)
|
||||
{
|
||||
butterfly_send(pgm, "e", 1);
|
||||
if (butterfly_vfy_cmd_sent(pgm, "chip erase") < 0)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static void butterfly_enter_prog_mode(PROGRAMMER * pgm)
|
||||
{
|
||||
butterfly_send(pgm, "P", 1);
|
||||
butterfly_vfy_cmd_sent(pgm, "enter prog mode");
|
||||
}
|
||||
|
||||
|
||||
static void butterfly_leave_prog_mode(PROGRAMMER * pgm)
|
||||
{
|
||||
butterfly_send(pgm, "L", 1);
|
||||
butterfly_vfy_cmd_sent(pgm, "leave prog mode");
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* issue the 'program enable' command to the AVR device
|
||||
*/
|
||||
static int butterfly_program_enable(PROGRAMMER * pgm, AVRPART * p)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* apply power to the AVR processor
|
||||
*/
|
||||
static void butterfly_powerup(PROGRAMMER * pgm)
|
||||
{
|
||||
/* Do nothing. */
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* remove power from the AVR processor
|
||||
*/
|
||||
static void butterfly_powerdown(PROGRAMMER * pgm)
|
||||
{
|
||||
/* Do nothing. */
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
#define IS_BUTTERFLY_MK 0x0001
|
||||
|
||||
/*
|
||||
* initialize the AVR device and prepare it to accept commands
|
||||
*/
|
||||
static int butterfly_initialize(PROGRAMMER * pgm, AVRPART * p)
|
||||
{
|
||||
char id[8];
|
||||
char sw[2];
|
||||
char hw[2];
|
||||
char buf[10];
|
||||
char type;
|
||||
char c, devtype_1st;
|
||||
|
||||
/*
|
||||
* Send some ESC to activate butterfly bootloader. This is not needed
|
||||
* for plain avr109 bootloaders but does not harm there either.
|
||||
*/
|
||||
avrdude_message(MSG_INFO, "Connecting to programmer: ");
|
||||
if (pgm->flag & IS_BUTTERFLY_MK)
|
||||
{
|
||||
char mk_reset_cmd[6] = {"#aR@S\r"};
|
||||
unsigned char mk_timeout = 0;
|
||||
|
||||
putc('.', stderr);
|
||||
butterfly_send(pgm, mk_reset_cmd, sizeof(mk_reset_cmd));
|
||||
usleep(20000);
|
||||
|
||||
do
|
||||
{
|
||||
c = 27;
|
||||
butterfly_send(pgm, &c, 1);
|
||||
usleep(20000);
|
||||
c = 0xaa;
|
||||
usleep(80000);
|
||||
butterfly_send(pgm, &c, 1);
|
||||
if (mk_timeout % 10 == 0) putc('.', stderr);
|
||||
} while (mk_timeout++ < 10);
|
||||
|
||||
butterfly_recv(pgm, &c, 1);
|
||||
if ( c != 'M' && c != '?')
|
||||
{
|
||||
avrdude_message(MSG_INFO, "\nConnection FAILED.");
|
||||
return -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
id[0] = 'M'; id[1] = 'K'; id[2] = '2'; id[3] = 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
do {
|
||||
putc('.', stderr);
|
||||
butterfly_send(pgm, "\033", 1);
|
||||
butterfly_drain(pgm, 0);
|
||||
butterfly_send(pgm, "S", 1);
|
||||
butterfly_recv(pgm, &c, 1);
|
||||
if (c != '?') {
|
||||
putc('\n', stderr);
|
||||
/*
|
||||
* Got a useful response, continue getting the programmer
|
||||
* identifier. Programmer returns exactly 7 chars _without_
|
||||
* the null.
|
||||
*/
|
||||
id[0] = c;
|
||||
butterfly_recv(pgm, &id[1], sizeof(id)-2);
|
||||
id[sizeof(id)-1] = '\0';
|
||||
}
|
||||
} while (c == '?');
|
||||
}
|
||||
|
||||
/* Get the HW and SW versions to see if the programmer is present. */
|
||||
butterfly_drain(pgm, 0);
|
||||
|
||||
butterfly_send(pgm, "V", 1);
|
||||
butterfly_recv(pgm, sw, sizeof(sw));
|
||||
|
||||
butterfly_send(pgm, "v", 1);
|
||||
butterfly_recv(pgm, hw, 1); /* first, read only _one_ byte */
|
||||
if (hw[0]!='?') {
|
||||
butterfly_recv(pgm, &hw[1], 1);/* now, read second byte */
|
||||
};
|
||||
|
||||
/* Get the programmer type (serial or parallel). Expect serial. */
|
||||
|
||||
butterfly_send(pgm, "p", 1);
|
||||
butterfly_recv(pgm, &type, 1);
|
||||
|
||||
avrdude_message(MSG_INFO, "Found programmer: Id = \"%s\"; type = %c\n", id, type);
|
||||
avrdude_message(MSG_INFO, " Software Version = %c.%c; ", sw[0], sw[1]);
|
||||
if (hw[0]=='?') {
|
||||
avrdude_message(MSG_INFO, "No Hardware Version given.\n");
|
||||
} else {
|
||||
avrdude_message(MSG_INFO, "Hardware Version = %c.%c\n", hw[0], hw[1]);
|
||||
};
|
||||
|
||||
/* See if programmer supports autoincrement of address. */
|
||||
|
||||
butterfly_send(pgm, "a", 1);
|
||||
butterfly_recv(pgm, &PDATA(pgm)->has_auto_incr_addr, 1);
|
||||
if (PDATA(pgm)->has_auto_incr_addr == 'Y')
|
||||
avrdude_message(MSG_INFO, "Programmer supports auto addr increment.\n");
|
||||
|
||||
/* Check support for buffered memory access, abort if not available */
|
||||
|
||||
butterfly_send(pgm, "b", 1);
|
||||
butterfly_recv(pgm, &c, 1);
|
||||
if (c != 'Y') {
|
||||
avrdude_message(MSG_INFO, "%s: error: buffered memory access not supported. Maybe it isn't\n"\
|
||||
"a butterfly/AVR109 but a AVR910 device?\n", progname);
|
||||
return -1;
|
||||
};
|
||||
butterfly_recv(pgm, &c, 1);
|
||||
PDATA(pgm)->buffersize = (unsigned int)(unsigned char)c<<8;
|
||||
butterfly_recv(pgm, &c, 1);
|
||||
PDATA(pgm)->buffersize += (unsigned int)(unsigned char)c;
|
||||
avrdude_message(MSG_INFO, "Programmer supports buffered memory access with buffersize=%i bytes.\n",
|
||||
PDATA(pgm)->buffersize);
|
||||
|
||||
/* Get list of devices that the programmer supports. */
|
||||
|
||||
butterfly_send(pgm, "t", 1);
|
||||
avrdude_message(MSG_INFO, "\nProgrammer supports the following devices:\n");
|
||||
devtype_1st = 0;
|
||||
while (1) {
|
||||
butterfly_recv(pgm, &c, 1);
|
||||
if (devtype_1st == 0)
|
||||
devtype_1st = c;
|
||||
|
||||
if (c == 0)
|
||||
break;
|
||||
avrdude_message(MSG_INFO, " Device code: 0x%02x\n", (unsigned int)(unsigned char)c);
|
||||
};
|
||||
avrdude_message(MSG_INFO, "\n");
|
||||
|
||||
/* Tell the programmer which part we selected.
|
||||
According to the AVR109 code, this is ignored by the bootloader. As
|
||||
some early versions might not properly ignore it, rather pick up the
|
||||
first device type as reported above than anything out of avrdude.conf,
|
||||
so to avoid a potential conflict. There appears to be no general
|
||||
agreement on AVR910 device IDs beyond the ones from the original
|
||||
appnote 910. */
|
||||
|
||||
buf[0] = 'T';
|
||||
buf[1] = devtype_1st;
|
||||
|
||||
butterfly_send(pgm, buf, 2);
|
||||
if (butterfly_vfy_cmd_sent(pgm, "select device") < 0)
|
||||
return -1;
|
||||
|
||||
if (verbose)
|
||||
avrdude_message(MSG_INFO, "%s: devcode selected: 0x%02x\n",
|
||||
progname, (unsigned)buf[1]);
|
||||
|
||||
butterfly_enter_prog_mode(pgm);
|
||||
butterfly_drain(pgm, 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void butterfly_disable(PROGRAMMER * pgm)
|
||||
{
|
||||
butterfly_leave_prog_mode(pgm);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
static void butterfly_enable(PROGRAMMER * pgm)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
static int butterfly_open(PROGRAMMER * pgm, char * port)
|
||||
{
|
||||
union pinfo pinfo;
|
||||
strcpy(pgm->port, port);
|
||||
/*
|
||||
* If baudrate was not specified use 19200 Baud
|
||||
*/
|
||||
if(pgm->baudrate == 0) {
|
||||
pgm->baudrate = 19200;
|
||||
}
|
||||
pinfo.serialinfo.baud = pgm->baudrate;
|
||||
pinfo.serialinfo.cflags = SERIAL_8N1;
|
||||
if (serial_open(port, pinfo, &pgm->fd)==-1) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* drain any extraneous input
|
||||
*/
|
||||
butterfly_drain (pgm, 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static void butterfly_close(PROGRAMMER * pgm)
|
||||
{
|
||||
/* "exit programmer" */
|
||||
butterfly_send(pgm, "E", 1);
|
||||
butterfly_vfy_cmd_sent(pgm, "exit bootloader");
|
||||
|
||||
serial_close(&pgm->fd);
|
||||
pgm->fd.ifd = -1;
|
||||
}
|
||||
|
||||
|
||||
static void butterfly_display(PROGRAMMER * pgm, const char * p)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
static void butterfly_set_addr(PROGRAMMER * pgm, unsigned long addr)
|
||||
{
|
||||
char cmd[3];
|
||||
|
||||
cmd[0] = 'A';
|
||||
cmd[1] = (addr >> 8) & 0xff;
|
||||
cmd[2] = addr & 0xff;
|
||||
|
||||
butterfly_send(pgm, cmd, sizeof(cmd));
|
||||
butterfly_vfy_cmd_sent(pgm, "set addr");
|
||||
}
|
||||
|
||||
|
||||
static void butterfly_set_extaddr(PROGRAMMER * pgm, unsigned long addr)
|
||||
{
|
||||
char cmd[4];
|
||||
|
||||
cmd[0] = 'H';
|
||||
cmd[1] = (addr >> 16) & 0xff;
|
||||
cmd[2] = (addr >> 8) & 0xff;
|
||||
cmd[3] = addr & 0xff;
|
||||
|
||||
butterfly_send(pgm, cmd, sizeof(cmd));
|
||||
butterfly_vfy_cmd_sent(pgm, "set extaddr");
|
||||
}
|
||||
|
||||
|
||||
|
||||
static int butterfly_write_byte(PROGRAMMER * pgm, AVRPART * p, AVRMEM * m,
|
||||
unsigned long addr, unsigned char value)
|
||||
{
|
||||
char cmd[6];
|
||||
int size;
|
||||
int use_ext_addr = m->op[AVR_OP_LOAD_EXT_ADDR] != NULL;
|
||||
|
||||
if ((strcmp(m->desc, "flash") == 0) || (strcmp(m->desc, "eeprom") == 0))
|
||||
{
|
||||
cmd[0] = 'B';
|
||||
cmd[1] = 0;
|
||||
if ((cmd[3] = toupper((int)(m->desc[0]))) == 'E') { /* write to eeprom */
|
||||
cmd[2] = 1;
|
||||
cmd[4] = value;
|
||||
size = 5;
|
||||
} else { /* write to flash */
|
||||
/* @@@ not yet implemented */
|
||||
cmd[2] = 2;
|
||||
size = 6;
|
||||
return -1;
|
||||
}
|
||||
if (use_ext_addr) {
|
||||
butterfly_set_extaddr(pgm, addr);
|
||||
} else {
|
||||
butterfly_set_addr(pgm, addr);
|
||||
}
|
||||
}
|
||||
else if (strcmp(m->desc, "lock") == 0)
|
||||
{
|
||||
cmd[0] = 'l';
|
||||
cmd[1] = value;
|
||||
size = 2;
|
||||
}
|
||||
else
|
||||
return -1;
|
||||
|
||||
butterfly_send(pgm, cmd, size);
|
||||
if (butterfly_vfy_cmd_sent(pgm, "write byte") < 0)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int butterfly_read_byte_flash(PROGRAMMER * pgm, AVRPART * p, AVRMEM * m,
|
||||
unsigned long addr, unsigned char * value)
|
||||
{
|
||||
static int cached = 0;
|
||||
static unsigned char cvalue;
|
||||
static unsigned long caddr;
|
||||
int use_ext_addr = m->op[AVR_OP_LOAD_EXT_ADDR] != NULL;
|
||||
|
||||
if (cached && ((caddr + 1) == addr)) {
|
||||
*value = cvalue;
|
||||
cached = 0;
|
||||
}
|
||||
else {
|
||||
char buf[2];
|
||||
|
||||
if (use_ext_addr) {
|
||||
butterfly_set_extaddr(pgm, addr >> 1);
|
||||
} else {
|
||||
butterfly_set_addr(pgm, addr >> 1);
|
||||
}
|
||||
|
||||
butterfly_send(pgm, "g\000\002F", 4);
|
||||
|
||||
/* Read back the program mem word (MSB first) */
|
||||
butterfly_recv(pgm, buf, sizeof(buf));
|
||||
|
||||
if ((addr & 0x01) == 0) {
|
||||
*value = buf[0];
|
||||
cached = 1;
|
||||
cvalue = buf[1];
|
||||
caddr = addr;
|
||||
}
|
||||
else {
|
||||
*value = buf[1];
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int butterfly_read_byte_eeprom(PROGRAMMER * pgm, AVRPART * p, AVRMEM * m,
|
||||
unsigned long addr, unsigned char * value)
|
||||
{
|
||||
butterfly_set_addr(pgm, addr);
|
||||
butterfly_send(pgm, "g\000\001E", 4);
|
||||
butterfly_recv(pgm, (char *)value, 1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int butterfly_page_erase(PROGRAMMER * pgm, AVRPART * p, AVRMEM * m, unsigned int addr)
|
||||
{
|
||||
if (strcmp(m->desc, "flash") == 0)
|
||||
return -1; /* not supported */
|
||||
if (strcmp(m->desc, "eeprom") == 0)
|
||||
return 0; /* nothing to do */
|
||||
avrdude_message(MSG_INFO, "%s: butterfly_page_erase() called on memory type \"%s\"\n",
|
||||
progname, m->desc);
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int butterfly_read_byte(PROGRAMMER * pgm, AVRPART * p, AVRMEM * m,
|
||||
unsigned long addr, unsigned char * value)
|
||||
{
|
||||
char cmd;
|
||||
|
||||
if (strcmp(m->desc, "flash") == 0) {
|
||||
return butterfly_read_byte_flash(pgm, p, m, addr, value);
|
||||
}
|
||||
|
||||
if (strcmp(m->desc, "eeprom") == 0) {
|
||||
return butterfly_read_byte_eeprom(pgm, p, m, addr, value);
|
||||
}
|
||||
|
||||
if (strcmp(m->desc, "lfuse") == 0) {
|
||||
cmd = 'F';
|
||||
}
|
||||
else if (strcmp(m->desc, "hfuse") == 0) {
|
||||
cmd = 'N';
|
||||
}
|
||||
else if (strcmp(m->desc, "efuse") == 0) {
|
||||
cmd = 'Q';
|
||||
}
|
||||
else if (strcmp(m->desc, "lock") == 0) {
|
||||
cmd = 'r';
|
||||
}
|
||||
else
|
||||
return -1;
|
||||
|
||||
butterfly_send(pgm, &cmd, 1);
|
||||
butterfly_recv(pgm, (char *)value, 1);
|
||||
|
||||
return *value == '?'? -1: 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static int butterfly_paged_write(PROGRAMMER * pgm, AVRPART * p, AVRMEM * m,
|
||||
unsigned int page_size,
|
||||
unsigned int addr, unsigned int n_bytes)
|
||||
{
|
||||
unsigned int max_addr = addr + n_bytes;
|
||||
char *cmd;
|
||||
unsigned int blocksize = PDATA(pgm)->buffersize;
|
||||
int use_ext_addr = m->op[AVR_OP_LOAD_EXT_ADDR] != NULL;
|
||||
unsigned int wr_size = 2;
|
||||
|
||||
if (strcmp(m->desc, "flash") && strcmp(m->desc, "eeprom"))
|
||||
return -2;
|
||||
|
||||
if (m->desc[0] == 'e')
|
||||
wr_size = blocksize = 1; /* Write to eeprom single bytes only */
|
||||
|
||||
if (use_ext_addr) {
|
||||
butterfly_set_extaddr(pgm, addr / wr_size);
|
||||
} else {
|
||||
butterfly_set_addr(pgm, addr / wr_size);
|
||||
}
|
||||
|
||||
#if 0
|
||||
usleep(1000000);
|
||||
butterfly_send(pgm, "y", 1);
|
||||
if (butterfly_vfy_cmd_sent(pgm, "clear LED") < 0)
|
||||
return -1;
|
||||
#endif
|
||||
|
||||
cmd = malloc(4+blocksize);
|
||||
if (!cmd) return -1;
|
||||
cmd[0] = 'B';
|
||||
cmd[3] = toupper((int)(m->desc[0]));
|
||||
|
||||
while (addr < max_addr) {
|
||||
if ((max_addr - addr) < blocksize) {
|
||||
blocksize = max_addr - addr;
|
||||
};
|
||||
memcpy(&cmd[4], &m->buf[addr], blocksize);
|
||||
cmd[1] = (blocksize >> 8) & 0xff;
|
||||
cmd[2] = blocksize & 0xff;
|
||||
|
||||
butterfly_send(pgm, cmd, 4+blocksize);
|
||||
if (butterfly_vfy_cmd_sent(pgm, "write block") < 0)
|
||||
return -1;
|
||||
|
||||
addr += blocksize;
|
||||
} /* while */
|
||||
free(cmd);
|
||||
|
||||
return addr;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static int butterfly_paged_load(PROGRAMMER * pgm, AVRPART * p, AVRMEM * m,
|
||||
unsigned int page_size,
|
||||
unsigned int addr, unsigned int n_bytes)
|
||||
{
|
||||
unsigned int max_addr = addr + n_bytes;
|
||||
int rd_size = 2;
|
||||
int blocksize = PDATA(pgm)->buffersize;
|
||||
int use_ext_addr = m->op[AVR_OP_LOAD_EXT_ADDR] != NULL;
|
||||
|
||||
/* check parameter syntax: only "flash" or "eeprom" is allowed */
|
||||
if (strcmp(m->desc, "flash") && strcmp(m->desc, "eeprom"))
|
||||
return -2;
|
||||
|
||||
if (m->desc[0] == 'e')
|
||||
rd_size = blocksize = 1; /* Read from eeprom single bytes only */
|
||||
|
||||
{ /* use buffered mode */
|
||||
char cmd[4];
|
||||
|
||||
cmd[0] = 'g';
|
||||
cmd[3] = toupper((int)(m->desc[0]));
|
||||
|
||||
if (use_ext_addr) {
|
||||
butterfly_set_extaddr(pgm, addr / rd_size);
|
||||
} else {
|
||||
butterfly_set_addr(pgm, addr / rd_size);
|
||||
}
|
||||
while (addr < max_addr) {
|
||||
if ((max_addr - addr) < blocksize) {
|
||||
blocksize = max_addr - addr;
|
||||
};
|
||||
cmd[1] = (blocksize >> 8) & 0xff;
|
||||
cmd[2] = blocksize & 0xff;
|
||||
|
||||
butterfly_send(pgm, cmd, 4);
|
||||
butterfly_recv(pgm, (char *)&m->buf[addr], blocksize);
|
||||
|
||||
addr += blocksize;
|
||||
} /* while */
|
||||
}
|
||||
|
||||
return addr * rd_size;
|
||||
}
|
||||
|
||||
|
||||
/* Signature byte reads are always 3 bytes. */
|
||||
static int butterfly_read_sig_bytes(PROGRAMMER * pgm, AVRPART * p, AVRMEM * m)
|
||||
{
|
||||
unsigned char tmp;
|
||||
|
||||
if (m->size < 3) {
|
||||
avrdude_message(MSG_INFO, "%s: memsize too small for sig byte read", progname);
|
||||
return -1;
|
||||
}
|
||||
|
||||
butterfly_send(pgm, "s", 1);
|
||||
butterfly_recv(pgm, (char *)m->buf, 3);
|
||||
/* Returned signature has wrong order. */
|
||||
tmp = m->buf[2];
|
||||
m->buf[2] = m->buf[0];
|
||||
m->buf[0] = tmp;
|
||||
|
||||
return 3;
|
||||
}
|
||||
|
||||
const char butterfly_desc[] = "Atmel Butterfly evaluation board; Atmel AppNotes AVR109, AVR911";
|
||||
|
||||
void butterfly_initpgm(PROGRAMMER * pgm)
|
||||
{
|
||||
strcpy(pgm->type, "butterfly");
|
||||
|
||||
/*
|
||||
* mandatory functions
|
||||
*/
|
||||
pgm->rdy_led = butterfly_rdy_led;
|
||||
pgm->err_led = butterfly_err_led;
|
||||
pgm->pgm_led = butterfly_pgm_led;
|
||||
pgm->vfy_led = butterfly_vfy_led;
|
||||
pgm->initialize = butterfly_initialize;
|
||||
pgm->display = butterfly_display;
|
||||
pgm->enable = butterfly_enable;
|
||||
pgm->disable = butterfly_disable;
|
||||
pgm->powerup = butterfly_powerup;
|
||||
pgm->powerdown = butterfly_powerdown;
|
||||
pgm->program_enable = butterfly_program_enable;
|
||||
pgm->chip_erase = butterfly_chip_erase;
|
||||
pgm->open = butterfly_open;
|
||||
pgm->close = butterfly_close;
|
||||
pgm->read_byte = butterfly_read_byte;
|
||||
pgm->write_byte = butterfly_write_byte;
|
||||
|
||||
/*
|
||||
* optional functions
|
||||
*/
|
||||
|
||||
pgm->page_erase = butterfly_page_erase;
|
||||
pgm->paged_write = butterfly_paged_write;
|
||||
pgm->paged_load = butterfly_paged_load;
|
||||
|
||||
pgm->read_sig_bytes = butterfly_read_sig_bytes;
|
||||
|
||||
pgm->setup = butterfly_setup;
|
||||
pgm->teardown = butterfly_teardown;
|
||||
pgm->flag = 0;
|
||||
}
|
||||
|
||||
const char butterfly_mk_desc[] = "Mikrokopter.de Butterfly";
|
||||
|
||||
void butterfly_mk_initpgm(PROGRAMMER * pgm)
|
||||
{
|
||||
butterfly_initpgm(pgm);
|
||||
strcpy(pgm->type, "butterfly_mk");
|
||||
pgm->flag = IS_BUTTERFLY_MK;
|
||||
}
|
||||
37
src/butterfly.h
Normal file
37
src/butterfly.h
Normal file
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* avrdude - A Downloader/Uploader for AVR device programmers
|
||||
* Copyright (C) 2003-2004 Theodore A. Roth <troth@openavr.org>
|
||||
*
|
||||
* 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/* $Id$ */
|
||||
|
||||
#ifndef butterfly_h
|
||||
#define butterfly_h
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
extern const char butterfly_desc[];
|
||||
extern const char butterfly_mk_desc[];
|
||||
void butterfly_initpgm (PROGRAMMER * pgm);
|
||||
void butterfly_mk_initpgm (PROGRAMMER * pgm);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* butterfly_h */
|
||||
351
src/config.c
Normal file
351
src/config.c
Normal file
@@ -0,0 +1,351 @@
|
||||
/*
|
||||
* avrdude - A Downloader/Uploader for AVR device programmers
|
||||
* Copyright (C) 2000-2004 Brian S. Dean <bsd@bsdhome.com>
|
||||
*
|
||||
* 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/* $Id$ */
|
||||
|
||||
#include "ac_cfg.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdarg.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "avrdude.h"
|
||||
#include "libavrdude.h"
|
||||
#include "config.h"
|
||||
|
||||
#include "config_gram.h"
|
||||
|
||||
char default_programmer[MAX_STR_CONST];
|
||||
char default_parallel[PATH_MAX];
|
||||
char default_serial[PATH_MAX];
|
||||
double default_bitclock;
|
||||
int default_safemode;
|
||||
|
||||
char string_buf[MAX_STR_CONST];
|
||||
char *string_buf_ptr;
|
||||
|
||||
LISTID string_list;
|
||||
LISTID number_list;
|
||||
PROGRAMMER * current_prog;
|
||||
AVRPART * current_part;
|
||||
AVRMEM * current_mem;
|
||||
LISTID part_list;
|
||||
LISTID programmers;
|
||||
|
||||
int lineno;
|
||||
const char * infile;
|
||||
|
||||
extern char * yytext;
|
||||
|
||||
#define DEBUG 0
|
||||
|
||||
void cleanup_config(void)
|
||||
{
|
||||
ldestroy_cb(part_list, (void(*)(void*))avr_free_part);
|
||||
ldestroy_cb(programmers, (void(*)(void*))pgm_free);
|
||||
ldestroy_cb(string_list, (void(*)(void*))free_token);
|
||||
ldestroy_cb(number_list, (void(*)(void*))free_token);
|
||||
}
|
||||
|
||||
int init_config(void)
|
||||
{
|
||||
string_list = lcreat(NULL, 0);
|
||||
number_list = lcreat(NULL, 0);
|
||||
current_prog = NULL;
|
||||
current_part = NULL;
|
||||
current_mem = NULL;
|
||||
part_list = lcreat(NULL, 0);
|
||||
programmers = lcreat(NULL, 0);
|
||||
|
||||
lineno = 1;
|
||||
infile = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int yywrap()
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
int yyerror(char * errmsg, ...)
|
||||
{
|
||||
va_list args;
|
||||
|
||||
char message[512];
|
||||
|
||||
va_start(args, errmsg);
|
||||
|
||||
vsnprintf(message, sizeof(message), errmsg, args);
|
||||
avrdude_message(MSG_INFO, "%s: error at %s:%d: %s\n", progname, infile, lineno, message);
|
||||
|
||||
va_end(args);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int yywarning(char * errmsg, ...)
|
||||
{
|
||||
va_list args;
|
||||
|
||||
char message[512];
|
||||
|
||||
va_start(args, errmsg);
|
||||
|
||||
vsnprintf(message, sizeof(message), errmsg, args);
|
||||
avrdude_message(MSG_INFO, "%s: warning at %s:%d: %s\n", progname, infile, lineno, message);
|
||||
|
||||
va_end(args);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
TOKEN * new_token(int primary)
|
||||
{
|
||||
TOKEN * tkn;
|
||||
|
||||
tkn = (TOKEN *)malloc(sizeof(TOKEN));
|
||||
if (tkn == NULL) {
|
||||
yyerror("new_token(): out of memory");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memset(tkn, 0, sizeof(TOKEN));
|
||||
|
||||
tkn->primary = primary;
|
||||
|
||||
return tkn;
|
||||
}
|
||||
|
||||
|
||||
void free_token(TOKEN * tkn)
|
||||
{
|
||||
if (tkn) {
|
||||
switch (tkn->value.type) {
|
||||
case V_STR:
|
||||
if (tkn->value.string)
|
||||
free(tkn->value.string);
|
||||
tkn->value.string = NULL;
|
||||
break;
|
||||
}
|
||||
|
||||
free(tkn);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void free_tokens(int n, ...)
|
||||
{
|
||||
TOKEN * t;
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, n);
|
||||
while (n--) {
|
||||
t = va_arg(ap, TOKEN *);
|
||||
free_token(t);
|
||||
}
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
|
||||
|
||||
TOKEN * number(char * text)
|
||||
{
|
||||
struct token_t * tkn;
|
||||
|
||||
tkn = new_token(TKN_NUMBER);
|
||||
if (tkn == NULL) {
|
||||
return NULL; /* yyerror already called */
|
||||
}
|
||||
tkn->value.type = V_NUM;
|
||||
tkn->value.number = atoi(text);
|
||||
|
||||
#if DEBUG
|
||||
avrdude_message(MSG_INFO, "NUMBER(%d)\n", tkn->value.number);
|
||||
#endif
|
||||
|
||||
return tkn;
|
||||
}
|
||||
|
||||
TOKEN * number_real(char * text)
|
||||
{
|
||||
struct token_t * tkn;
|
||||
|
||||
tkn = new_token(TKN_NUMBER);
|
||||
tkn->value.type = V_NUM_REAL;
|
||||
tkn->value.number_real = atof(text);
|
||||
|
||||
#if DEBUG
|
||||
avrdude_message(MSG_INFO, "NUMBER(%g)\n", tkn->value.number_real);
|
||||
#endif
|
||||
|
||||
return tkn;
|
||||
}
|
||||
|
||||
TOKEN * hexnumber(char * text)
|
||||
{
|
||||
struct token_t * tkn;
|
||||
char * e;
|
||||
|
||||
tkn = new_token(TKN_NUMBER);
|
||||
if (tkn == NULL) {
|
||||
return NULL; /* yyerror already called */
|
||||
}
|
||||
tkn->value.type = V_NUM;
|
||||
tkn->value.number = strtoul(text, &e, 16);
|
||||
if ((e == text) || (*e != 0)) {
|
||||
yyerror("can't scan hex number \"%s\"", text);
|
||||
free_token(tkn);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#if DEBUG
|
||||
avrdude_message(MSG_INFO, "HEXNUMBER(%g)\n", tkn->value.number);
|
||||
#endif
|
||||
|
||||
return tkn;
|
||||
}
|
||||
|
||||
|
||||
TOKEN * string(char * text)
|
||||
{
|
||||
struct token_t * tkn;
|
||||
int len;
|
||||
|
||||
tkn = new_token(TKN_STRING);
|
||||
if (tkn == NULL) {
|
||||
return NULL; /* yyerror already called */
|
||||
}
|
||||
|
||||
len = strlen(text);
|
||||
|
||||
tkn->value.type = V_STR;
|
||||
tkn->value.string = (char *) malloc(len+1);
|
||||
if (tkn->value.string == NULL) {
|
||||
yyerror("string(): out of memory");
|
||||
free_token(tkn);
|
||||
return NULL;
|
||||
}
|
||||
strcpy(tkn->value.string, text);
|
||||
|
||||
#if DEBUG
|
||||
avrdude_message(MSG_INFO, "STRING(%s)\n", tkn->value.string);
|
||||
#endif
|
||||
|
||||
return tkn;
|
||||
}
|
||||
|
||||
|
||||
TOKEN * keyword(int primary)
|
||||
{
|
||||
struct token_t * tkn;
|
||||
|
||||
tkn = new_token(primary);
|
||||
|
||||
return tkn;
|
||||
}
|
||||
|
||||
|
||||
void print_token(TOKEN * tkn)
|
||||
{
|
||||
if (!tkn)
|
||||
return;
|
||||
|
||||
avrdude_message(MSG_INFO, "token = %d = ", tkn->primary);
|
||||
switch (tkn->value.type) {
|
||||
case V_NUM:
|
||||
avrdude_message(MSG_INFO, "NUMBER, value=%d", tkn->value.number);
|
||||
break;
|
||||
|
||||
case V_NUM_REAL:
|
||||
avrdude_message(MSG_INFO, "NUMBER, value=%g", tkn->value.number_real);
|
||||
break;
|
||||
|
||||
case V_STR:
|
||||
avrdude_message(MSG_INFO, "STRING, value=%s", tkn->value.string);
|
||||
break;
|
||||
|
||||
default:
|
||||
avrdude_message(MSG_INFO, "<other>");
|
||||
break;
|
||||
}
|
||||
|
||||
avrdude_message(MSG_INFO, "\n");
|
||||
}
|
||||
|
||||
|
||||
void pyytext(void)
|
||||
{
|
||||
#if DEBUG
|
||||
avrdude_message(MSG_INFO, "TOKEN: \"%s\"\n", yytext);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
char * dup_string(const char * str)
|
||||
{
|
||||
char * s;
|
||||
|
||||
s = strdup(str);
|
||||
if (s == NULL) {
|
||||
yyerror("dup_string(): out of memory");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
#ifdef HAVE_YYLEX_DESTROY
|
||||
/* reset lexer and free any allocated memory */
|
||||
extern int yylex_destroy(void);
|
||||
#endif
|
||||
|
||||
int read_config(const char * file)
|
||||
{
|
||||
FILE * f;
|
||||
int r;
|
||||
|
||||
f = fopen(file, "r");
|
||||
if (f == NULL) {
|
||||
avrdude_message(MSG_INFO, "%s: can't open config file \"%s\": %s\n",
|
||||
progname, file, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
lineno = 1;
|
||||
infile = file;
|
||||
yyin = f;
|
||||
|
||||
r = yyparse();
|
||||
|
||||
#ifdef HAVE_YYLEX_DESTROY
|
||||
/* reset lexer and free any allocated memory */
|
||||
yylex_destroy();
|
||||
#endif
|
||||
|
||||
fclose(f);
|
||||
|
||||
return r;
|
||||
}
|
||||
103
src/config.h
Normal file
103
src/config.h
Normal file
@@ -0,0 +1,103 @@
|
||||
/*
|
||||
* avrdude - A Downloader/Uploader for AVR device programmers
|
||||
* Copyright (C) 2000-2004 Brian S. Dean <bsd@bsdhome.com>
|
||||
*
|
||||
* 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/* $Id$ */
|
||||
|
||||
/* These are the internal definitions needed for config parsing */
|
||||
|
||||
#ifndef config_h
|
||||
#define config_h
|
||||
|
||||
#include "libavrdude.h"
|
||||
|
||||
|
||||
#define MAX_STR_CONST 1024
|
||||
|
||||
enum { V_NONE, V_NUM, V_NUM_REAL, V_STR };
|
||||
typedef struct value_t {
|
||||
int type;
|
||||
/*union { TODO: use an anonymous union here ? */
|
||||
int number;
|
||||
double number_real;
|
||||
char * string;
|
||||
/*};*/
|
||||
} VALUE;
|
||||
|
||||
|
||||
typedef struct token_t {
|
||||
int primary;
|
||||
VALUE value;
|
||||
} TOKEN;
|
||||
typedef struct token_t *token_p;
|
||||
|
||||
|
||||
extern FILE * yyin;
|
||||
extern PROGRAMMER * current_prog;
|
||||
extern AVRPART * current_part;
|
||||
extern AVRMEM * current_mem;
|
||||
extern int lineno;
|
||||
extern const char * infile;
|
||||
extern LISTID string_list;
|
||||
extern LISTID number_list;
|
||||
|
||||
|
||||
#if !defined(HAS_YYSTYPE)
|
||||
#define YYSTYPE token_p
|
||||
#endif
|
||||
extern YYSTYPE yylval;
|
||||
|
||||
extern char string_buf[MAX_STR_CONST];
|
||||
extern char *string_buf_ptr;
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
int yyparse(void);
|
||||
|
||||
int yyerror(char * errmsg, ...);
|
||||
|
||||
int yywarning(char * errmsg, ...);
|
||||
|
||||
TOKEN * new_token(int primary);
|
||||
|
||||
void free_token(TOKEN * tkn);
|
||||
|
||||
void free_tokens(int n, ...);
|
||||
|
||||
TOKEN * number(char * text);
|
||||
|
||||
TOKEN * number_real(char * text);
|
||||
|
||||
TOKEN * hexnumber(char * text);
|
||||
|
||||
TOKEN * string(char * text);
|
||||
|
||||
TOKEN * keyword(int primary);
|
||||
|
||||
void print_token(TOKEN * tkn);
|
||||
|
||||
void pyytext(void);
|
||||
|
||||
char * dup_string(const char * str);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
1603
src/config_gram.y
Normal file
1603
src/config_gram.y
Normal file
File diff suppressed because it is too large
Load Diff
615
src/configure.ac
Normal file
615
src/configure.ac
Normal file
@@ -0,0 +1,615 @@
|
||||
#
|
||||
# avrdude - A Downloader/Uploader for AVR device programmers
|
||||
# Copyright (C) 2003, 2004 Theodore A. Roth <troth@openavr.org>
|
||||
#
|
||||
# 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, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
|
||||
#
|
||||
# $Id$
|
||||
#
|
||||
|
||||
# Process this file with autoconf to produce a configure script.
|
||||
|
||||
AC_PREREQ(2.60)
|
||||
AC_INIT(avrdude, 6.99-20211218, avrdude-dev@nongnu.org)
|
||||
|
||||
AC_CANONICAL_BUILD
|
||||
AC_CANONICAL_HOST
|
||||
AC_CANONICAL_TARGET
|
||||
|
||||
AC_CONFIG_SRCDIR([main.c])
|
||||
AM_INIT_AUTOMAKE([foreign])
|
||||
AC_CONFIG_HEADERS(ac_cfg.h)
|
||||
AC_CONFIG_MACRO_DIR([m4])
|
||||
|
||||
LT_INIT()
|
||||
|
||||
m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])])
|
||||
|
||||
# Checks for programs.
|
||||
AC_PROG_CC
|
||||
AC_PROG_INSTALL
|
||||
AC_PROG_SED
|
||||
AC_PROG_YACC
|
||||
AC_PROG_LEX
|
||||
AN_MAKEVAR([AR], [AC_PROG_AR])
|
||||
AN_PROGRAM([ar], [AC_PROG_AR])
|
||||
AC_DEFUN([AC_PROG_AR], [AC_CHECK_TARGET_TOOL(AR, ar, :)])
|
||||
AC_PROG_AR
|
||||
AH_TEMPLATE([HAVE_YYLEX_DESTROY],
|
||||
[Define if lex/flex has yylex_destroy])
|
||||
# flex should have this
|
||||
if test "x$LEX" == xflex; then
|
||||
AC_MSG_CHECKING([whether yylex_destroy is generated by flex])
|
||||
flex_version=`$LEX -V -v --version 2>/dev/null | $SED -e 's/^.* //'`
|
||||
case $flex_version in
|
||||
[[0-1].*)]
|
||||
AC_MSG_RESULT([version $flex_version => no])
|
||||
;;
|
||||
[2.[0-4].*)]
|
||||
AC_MSG_RESULT([version $flex_version => no])
|
||||
;;
|
||||
[2.5.[0-8])]
|
||||
AC_MSG_RESULT([version $flex_version => no])
|
||||
;;
|
||||
[2.5.[0-8][A-Za-z]*)]
|
||||
AC_MSG_RESULT([version $flex_version => no])
|
||||
;;
|
||||
*)
|
||||
AC_MSG_RESULT([version $flex_version => yes])
|
||||
AC_DEFINE([HAVE_YYLEX_DESTROY])
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
|
||||
dnl Makefile.am:77: compiling `config_gram.c' with per-target flags requires `AM_PROG_CC_C_O' in `configure.ac'
|
||||
AM_PROG_CC_C_O
|
||||
|
||||
# Checks for libraries.
|
||||
AC_CHECK_LIB([termcap], [tputs])
|
||||
AC_CHECK_LIB([ncurses], [tputs])
|
||||
AC_CHECK_LIB([readline], [readline])
|
||||
AH_TEMPLATE([HAVE_LIBELF],
|
||||
[Define if ELF support is enabled via libelf])
|
||||
AC_CHECK_LIB([elf], [elf_getshdrstrndx], [have_libelf=yes])
|
||||
if test x$have_libelf = xyes; then
|
||||
case $target in
|
||||
*)
|
||||
LIBELF="-lelf"
|
||||
;;
|
||||
esac
|
||||
AC_DEFINE([HAVE_LIBELF])
|
||||
AC_CHECK_HEADERS([libelf.h libelf/libelf.h])
|
||||
fi
|
||||
AC_SUBST(LIBELF, $LIBELF)
|
||||
|
||||
AC_SEARCH_LIBS([gethostent], [nsl])
|
||||
AC_SEARCH_LIBS([setsockopt], [socket])
|
||||
AH_TEMPLATE([HAVE_LIBUSB],
|
||||
[Define if USB support is enabled via libusb])
|
||||
AC_CHECK_LIB([usb], [usb_get_string_simple], [have_libusb=yes])
|
||||
if test x$have_libusb = xyes; then
|
||||
case $target in
|
||||
*-*-darwin*)
|
||||
LIBUSB="-lusb -framework CoreFoundation -framework IOKit"
|
||||
;;
|
||||
*)
|
||||
LIBUSB="-lusb"
|
||||
;;
|
||||
esac
|
||||
AC_DEFINE([HAVE_LIBUSB])
|
||||
AC_CHECK_HEADERS([usb.h])
|
||||
AC_CHECK_HEADERS([lusb0_usb.h])
|
||||
fi
|
||||
AC_SUBST(LIBUSB, $LIBUSB)
|
||||
|
||||
AC_ARG_ENABLE(
|
||||
[libusb_1_0],
|
||||
AC_HELP_STRING(
|
||||
[--disable-libusb_1_0],
|
||||
[Allow to build with libusb instead of libusb_1_0 if both are present]),
|
||||
[case "${enableval}" in
|
||||
yes) enabled_libusb_1_0=yes ;;
|
||||
no) enabled_libusb_1_0=no ;;
|
||||
*) AC_MSG_ERROR(bad value ${enableval} for enable-libusb_1_0 option) ;;
|
||||
esac],
|
||||
[enabled_libusb_1_0=yes])
|
||||
|
||||
AH_TEMPLATE([HAVE_LIBUSB_1_0],
|
||||
[Define if USB support is enabled via libusb 1.0])
|
||||
AC_CHECK_LIB([usb-1.0], [libusb_init], [have_libusb_1_0=yes])
|
||||
if test x$have_libusb_1_0 = xyes && test x$enabled_libusb_1_0 = xyes; then
|
||||
case $target in
|
||||
*-*-darwin*)
|
||||
LIBUSB_1_0="-lusb-1.0 -framework CoreFoundation -framework IOKit"
|
||||
;;
|
||||
*)
|
||||
LIBUSB_1_0="-lusb-1.0"
|
||||
;;
|
||||
esac
|
||||
AC_DEFINE([HAVE_LIBUSB_1_0])
|
||||
AC_CHECK_HEADERS([libusb-1.0/libusb.h])
|
||||
AC_CHECK_HEADERS([libusb.h])
|
||||
fi
|
||||
AH_TEMPLATE([HAVE_LIBUSB_1_0],
|
||||
[Define if USB support is enabled via a libusb-1.0 compatible libusb])
|
||||
AC_CHECK_LIB([usb], [libusb_init], [have_libusb_1_0=yes])
|
||||
if test x$have_libusb_1_0 = xyes && test x$enabled_libusb_1_0 = xyes; then
|
||||
case $target in
|
||||
*-*-freebsd*)
|
||||
# FreeBSD 8+ has a native libusb-1.0 API compatible
|
||||
# library offered by -lusb (which is also libusb-0.1
|
||||
# compatible). FreeBSD <8 does not have a libusb-1.0
|
||||
# at all so probing will fail but we do not have to
|
||||
# special-case that.
|
||||
LIBUSB_1_0="-lusb"
|
||||
;;
|
||||
*)
|
||||
LIBUSB_1_0="-lusb-1.0"
|
||||
;;
|
||||
esac
|
||||
AC_DEFINE([HAVE_LIBUSB_1_0])
|
||||
AC_CHECK_HEADERS([libusb.h])
|
||||
fi
|
||||
AC_SUBST(LIBUSB_1_0, $LIBUSB_1_0)
|
||||
|
||||
AH_TEMPLATE([HAVE_LIBHIDAPI],
|
||||
[Define if HID support is enabled via libhidapi])
|
||||
AC_SEARCH_LIBS([hid_init], [hidapi hidapi-libusb hidapi-hidraw], [have_libhidapi=yes])
|
||||
if test x$have_libhidapi = xyes; then
|
||||
case $target in
|
||||
*-*-darwin*)
|
||||
LIBHIDAPI="-lhidapi -iframework CoreFoundation -framework IOKit"
|
||||
;;
|
||||
*)
|
||||
LIBHIDAPI="$ac_cv_lib_hid_init"
|
||||
;;
|
||||
esac
|
||||
AC_DEFINE([HAVE_LIBHIDAPI])
|
||||
AC_CHECK_HEADERS([hidapi/hidapi.h])
|
||||
fi
|
||||
AC_SUBST(LIBHIDAPI, $LIBHIDAPI)
|
||||
|
||||
|
||||
AH_TEMPLATE([HAVE_LIBFTDI1],
|
||||
[Define if FTDI support is enabled via libftdi1])
|
||||
AH_TEMPLATE([HAVE_LIBFTDI],
|
||||
[Define if FTDI support is enabled via libftdi])
|
||||
AH_TEMPLATE([HAVE_LIBFTDI_TYPE_232H],
|
||||
[Define if libftdi supports FT232H, libftdi version >= 0.20])
|
||||
AC_CHECK_LIB([ftdi1], [ftdi_new], [have_libftdi1=yes], [], [$LIBUSB_1_0])
|
||||
AC_CHECK_LIB([ftdi], [ftdi_usb_get_strings], [have_libftdi=yes], [], [-lusb])
|
||||
if test x$have_libftdi1 = xyes; then
|
||||
LIBFTDI1="-lftdi1"
|
||||
AC_DEFINE([HAVE_LIBFTDI1])
|
||||
AC_SUBST(LIBFTDI1, $LIBFTDI1)
|
||||
else
|
||||
if test x$have_libftdi = xyes; then
|
||||
LIBFTDI="-lftdi -lusb"
|
||||
AC_DEFINE([HAVE_LIBFTDI])
|
||||
AC_SUBST(LIBFTDI, $LIBFTDI)
|
||||
AC_CHECK_DECL(TYPE_232H,[have_libftdi_FT232H=yes], [], [[#include <ftdi.h>]])
|
||||
if test x$have_libftdi_FT232H = xyes; then
|
||||
AC_DEFINE([HAVE_LIBFTDI_TYPE_232H])
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
AC_CHECK_HEADERS([pthread.h])
|
||||
# as there exits header file only pthread implementations for Windows, check if we have a library
|
||||
AC_CHECK_LIB([pthread], [pthread_create], [have_pthread=yes])
|
||||
if test x$have_pthread = xyes; then
|
||||
LIBPTHREAD="-lpthread"
|
||||
fi
|
||||
AC_SUBST(LIBPTHREAD, $LIBPTHREAD)
|
||||
# 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])
|
||||
AC_CHECK_HEADERS([ddk/hidsdi.h],,,[#include <windows.h>
|
||||
#include <setupapi.h>])
|
||||
|
||||
|
||||
# Checks for typedefs, structures, and compiler characteristics.
|
||||
AC_C_CONST
|
||||
AC_HEADER_TIME
|
||||
|
||||
AC_CHECK_HEADERS([netinet/in.h])
|
||||
|
||||
# WinSock2
|
||||
AC_CHECK_LIB([ws2_32], [puts])
|
||||
|
||||
# Checks for library functions.
|
||||
AC_CHECK_FUNCS([memset select strcasecmp strdup strerror strncasecmp strtol strtoul gettimeofday usleep getaddrinfo])
|
||||
|
||||
AC_MSG_CHECKING([for a Win32 HID libray])
|
||||
SAVED_LIBS="${LIBS}"
|
||||
case $target in
|
||||
*-*-mingw32* | *-*-cygwin* | *-*-windows*)
|
||||
LIBHID="-lhid -lsetupapi"
|
||||
if test $ac_cv_header_ddk_hidsdi_h = yes
|
||||
then
|
||||
HIDINCLUDE="#include <ddk/hidsdi.h>"
|
||||
else
|
||||
HIDINCLUDE="#include \"my_ddk_hidsdi.h\""
|
||||
fi
|
||||
;;
|
||||
*)
|
||||
LIBHID=""
|
||||
;;
|
||||
esac
|
||||
LIBS="${LIBS} ${LIBHID}"
|
||||
|
||||
AH_TEMPLATE([HAVE_LIBHID],
|
||||
[Define if HID support is enabled via the Win32 DDK])
|
||||
AC_TRY_LINK([#include <windows.h>
|
||||
#include <setupapi.h>
|
||||
$HIDINCLUDE],
|
||||
[int
|
||||
main(void)
|
||||
{
|
||||
GUID hidGuid;
|
||||
HidD_GetHidGuid(&hidGuid);
|
||||
|
||||
return 0;
|
||||
}
|
||||
], [have_libhid=yes], [have_libhid=no])
|
||||
AC_MSG_RESULT([$have_libhid])
|
||||
if test x$have_libhid = xyes; then
|
||||
AC_DEFINE([HAVE_LIBHID])
|
||||
else
|
||||
LIBHID=""
|
||||
fi
|
||||
LIBS="${SAVED_LIBS}"
|
||||
AC_SUBST(LIBHID, $LIBHID)
|
||||
|
||||
# Check for types
|
||||
|
||||
# Solaris has uint_t and ulong_t typedefs in <sys/types.h>, avoid
|
||||
# the redeclaration in usbtiny.c.
|
||||
AC_CHECK_TYPES([uint_t], [], [], [#include <sys/types.h>])
|
||||
AC_CHECK_TYPES([ulong_t], [], [], [#include <sys/types.h>])
|
||||
|
||||
# Checks for misc stuff.
|
||||
|
||||
AC_ARG_ENABLE(
|
||||
[versioned-doc],
|
||||
AC_HELP_STRING(
|
||||
[--enable-versioned-doc],
|
||||
[install docs in directory with version name (default)]),
|
||||
[case "${enableval}" in
|
||||
yes) versioned_doc=yes ;;
|
||||
no) versioned_doc=no ;;
|
||||
*) AC_MSG_ERROR(bad value ${enableval} for versioned-doc option) ;;
|
||||
esac],
|
||||
[versioned_doc=yes])
|
||||
|
||||
if test "$versioned_doc" = "yes"; then
|
||||
DOC_INST_DIR='$(DESTDIR)$(datadir)/doc/avrdude-$(VERSION)'
|
||||
else
|
||||
DOC_INST_DIR='$(DESTDIR)$(datadir)/doc/avrdude'
|
||||
fi
|
||||
|
||||
AC_ARG_ENABLE(
|
||||
[doc],
|
||||
AC_HELP_STRING(
|
||||
[--enable-doc],
|
||||
[Enable building documents]),
|
||||
[case "${enableval}" in
|
||||
yes) enabled_doc=yes ;;
|
||||
no) enabled_doc=no ;;
|
||||
*) AC_MSG_ERROR(bad value ${enableval} for disable-doc option) ;;
|
||||
esac],
|
||||
[enabled_doc=no])
|
||||
|
||||
AC_ARG_ENABLE(
|
||||
[parport],
|
||||
AC_HELP_STRING(
|
||||
[--enable-parport],
|
||||
[Enable accessing parallel ports(default)]),
|
||||
[case "${enableval}" in
|
||||
yes) enabled_parport=yes ;;
|
||||
no) enabled_parport=no ;;
|
||||
*) AC_MSG_ERROR(bad value ${enableval} for enable-parport option) ;;
|
||||
esac],
|
||||
[enabled_parport=no])
|
||||
|
||||
AC_ARG_ENABLE(
|
||||
[linuxgpio],
|
||||
AC_HELP_STRING(
|
||||
[--enable-linuxgpio],
|
||||
[Enable the Linux sysfs GPIO interface programmer type]),
|
||||
[case "${enableval}" in
|
||||
yes) enabled_linuxgpio=yes ;;
|
||||
no) enabled_linuxgpio=no ;;
|
||||
*) AC_MSG_ERROR(bad value ${enableval} for enable-linuxgpio option) ;;
|
||||
esac],
|
||||
[enabled_linuxgpio=no])
|
||||
|
||||
AC_ARG_ENABLE(
|
||||
[linuxspi],
|
||||
AC_HELP_STRING(
|
||||
[--enable-linuxspi],
|
||||
[Enable the Linux SPIDEV interface programmer type]),
|
||||
[case "${enableval}" in
|
||||
yes) enabled_linuxspi=yes ;;
|
||||
no) enabled_linuxspi=no ;;
|
||||
*) AC_MSG_ERROR(bad value ${enableval} for enable-linuxspi option) ;;
|
||||
esac],
|
||||
[enabled_linuxspi=no])
|
||||
|
||||
DIST_SUBDIRS_AC='doc'
|
||||
|
||||
if test "$enabled_doc" = "yes"; then
|
||||
SUBDIRS_AC='doc'
|
||||
else
|
||||
SUBDIRS_AC=''
|
||||
fi
|
||||
|
||||
AC_SUBST(DOC_INST_DIR, $DOC_INST_DIR)
|
||||
AC_SUBST(SUBDIRS_AC, $SUBDIRS_AC)
|
||||
AC_SUBST(DIST_SUBDIRS_AC, $DIST_SUBDIRS_AC)
|
||||
|
||||
|
||||
# Find the parallel serial device files based on target system
|
||||
# If a system doesn't have a PC style parallel, mark it as unknown.
|
||||
case $target in
|
||||
i[[3456]]86-*-linux*|x86_64-*-linux*)
|
||||
DEFAULT_PAR_PORT="/dev/parport0"
|
||||
DEFAULT_SER_PORT="/dev/ttyS0"
|
||||
;;
|
||||
*-*-linux*)
|
||||
DEFAULT_PAR_PORT="unknown"
|
||||
DEFAULT_SER_PORT="/dev/ttyS0"
|
||||
;;
|
||||
i[[3456]]86-*-*freebsd*|amd64-*-*freebsd*)
|
||||
DEFAULT_PAR_PORT="/dev/ppi0"
|
||||
DEFAULT_SER_PORT="/dev/cuad0"
|
||||
;;
|
||||
*-*-*freebsd*)
|
||||
DEFAULT_PAR_PORT="unknown"
|
||||
DEFAULT_SER_PORT="/dev/cuad0"
|
||||
;;
|
||||
*-*-solaris*)
|
||||
DEFAULT_PAR_PORT="/dev/printers/0"
|
||||
DEFAULT_SER_PORT="/dev/term/a"
|
||||
;;
|
||||
*-*-msdos* | *-*-mingw32* | *-*-cygwin* | *-*-windows*)
|
||||
DEFAULT_PAR_PORT="lpt1"
|
||||
DEFAULT_SER_PORT="com1"
|
||||
;;
|
||||
*)
|
||||
DEFAULT_PAR_PORT="unknown"
|
||||
DEFAULT_SER_PORT="unknown"
|
||||
;;
|
||||
esac
|
||||
|
||||
if test "$enabled_parport" = "yes"; then
|
||||
AC_MSG_CHECKING([for parallel device])
|
||||
if test "$DEFAULT_PAR_PORT" = "unknown"; then
|
||||
AC_MSG_NOTICE([parallel port access disabled for this system])
|
||||
enabled_parport=no
|
||||
else
|
||||
AC_MSG_RESULT([$DEFAULT_PAR_PORT])
|
||||
fi
|
||||
AC_SUBST(DEFAULT_PAR_PORT, $DEFAULT_PAR_PORT)
|
||||
fi
|
||||
|
||||
AC_MSG_CHECKING([for serial device])
|
||||
AC_MSG_RESULT([$DEFAULT_SER_PORT])
|
||||
AC_SUBST(DEFAULT_SER_PORT, $DEFAULT_SER_PORT)
|
||||
|
||||
if test "$enabled_parport" = "yes"; then
|
||||
AC_DEFINE(HAVE_PARPORT, 1, [parallel port access enabled])
|
||||
confsubst="-e /^@HAVE_PARPORT_/d"
|
||||
else
|
||||
confsubst="-e /^@HAVE_PARPORT_BEGIN@/,/^@HAVE_PARPORT_END@/d"
|
||||
fi
|
||||
|
||||
|
||||
if test "$enabled_linuxgpio" = "yes"; then
|
||||
AC_DEFINE(HAVE_LINUXGPIO, 1, [Linux sysfs GPIO support enabled])
|
||||
confsubst="$confsubst -e /^@HAVE_LINUXGPIO_/d"
|
||||
else
|
||||
confsubst="$confsubst -e /^@HAVE_LINUXGPIO_BEGIN@/,/^@HAVE_LINUXGPIO_END@/d"
|
||||
fi
|
||||
|
||||
|
||||
if test "$enabled_linuxspi" = "yes"; then
|
||||
AC_DEFINE(HAVE_LINUXSPI, 1, [Linux SPI support enabled])
|
||||
confsubst="$confsubst -e /^@HAVE_LINUXSPI_/d"
|
||||
else
|
||||
confsubst="$confsubst -e /^@HAVE_LINUXSPI_BEGIN@/,/^@HAVE_LINUXSPI_END@/d"
|
||||
fi
|
||||
|
||||
|
||||
# If we are compiling with gcc, enable all warning and make warnings errors.
|
||||
if test "$GCC" = yes; then
|
||||
ENABLE_WARNINGS="-Wall"
|
||||
|
||||
# does this compiler support -Wno-pointer-sign ?
|
||||
AC_MSG_CHECKING([if gcc accepts -Wno-pointer-sign ])
|
||||
|
||||
safe_CFLAGS=$CFLAGS
|
||||
CFLAGS="$ENABLE_WARNINGS -Wno-pointer-sign"
|
||||
|
||||
AC_TRY_COMPILE(, [ int main () { return 0 ; } ], [
|
||||
no_pointer_sign=yes
|
||||
AC_MSG_RESULT([yes])
|
||||
], [
|
||||
no_pointer_sign=no
|
||||
AC_MSG_RESULT([no])
|
||||
])
|
||||
CFLAGS=$safe_CFLAGS
|
||||
|
||||
if test x$no_pointer_sign = xyes; then
|
||||
ENABLE_WARNINGS="$ENABLE_WARNINGS -Wno-pointer-sign"
|
||||
fi
|
||||
fi
|
||||
AC_SUBST(ENABLE_WARNINGS,$ENABLE_WARNINGS)
|
||||
|
||||
# See if we need to drop into the windows subdir.
|
||||
case $target in
|
||||
*-*-mingw32* | *-*-cygwin* | *-*-windows*)
|
||||
if test "$GCC" = yes -a \( "$CC" = "cc" -o "$CC" = "gcc" \); then
|
||||
# does this compiler support -mno-cygwin?
|
||||
AC_MSG_CHECKING([if $CC accepts -mno-cygwin])
|
||||
|
||||
safe_CFLAGS="$CFLAGS"
|
||||
CFLAGS="$ENABLE_WARNINGS -mno-cygwin"
|
||||
|
||||
AC_TRY_COMPILE(, [ int main () { return 0 ; } ], [
|
||||
no_cygwin=yes
|
||||
AC_MSG_RESULT([yes])
|
||||
], [
|
||||
no_cygwin=no
|
||||
AC_MSG_RESULT([no])
|
||||
])
|
||||
CFLAGS="$safe_CFLAGS"
|
||||
|
||||
if test x$no_cygwin = xyes; then
|
||||
CFLAGS="${CFLAGS} -mno-cygwin"
|
||||
else
|
||||
AC_MSG_NOTICE([Your compiler does not understand the -mno-cygwin option.])
|
||||
AC_MSG_NOTICE([You might want to select an alternative compiler, like])
|
||||
AC_MSG_NOTICE([])
|
||||
AC_MSG_NOTICE([CC=mingw32-gcc ./configure])
|
||||
AC_MSG_NOTICE([])
|
||||
fi
|
||||
fi
|
||||
|
||||
AC_MSG_CHECKING([if linker accepts -static])
|
||||
|
||||
safe_LDFLAGS="$LDFLAGS"
|
||||
LDFLAGS="${LDFLAGS} -static"
|
||||
AC_TRY_LINK(, [ int main () { return 0 ; } ], [
|
||||
can_link_static=yes
|
||||
AC_MSG_RESULT([yes])
|
||||
], [
|
||||
can_link_static_cygwin=no
|
||||
AC_MSG_RESULT([no])
|
||||
])
|
||||
LDFLAGS="$safe_LDFLAGS"
|
||||
|
||||
if test x$can_link_static = xyes; then
|
||||
LDFLAGS="${LDFLAGS} -static"
|
||||
fi
|
||||
|
||||
CFLAGS="${CFLAGS} -DWIN32NATIVE"
|
||||
;;
|
||||
esac
|
||||
|
||||
AC_CONFIG_FILES([
|
||||
doc/Makefile
|
||||
avrdude.spec
|
||||
Makefile
|
||||
])
|
||||
|
||||
# The procedure to create avrdude.conf involves two steps. First,
|
||||
# normal autoconf substitution will be applied, resulting in
|
||||
# avrdude.conf.tmp. Finally, a sed command will be applied to filter
|
||||
# out unwanted parts (currently the parallel port programmer types)
|
||||
# based on previous configuration results, thereby producing the final
|
||||
# avrdude.conf file.
|
||||
|
||||
AC_CONFIG_FILES([avrdude.conf.tmp:avrdude.conf.in],
|
||||
[sed $confsubst avrdude.conf.tmp > avrdude.conf],
|
||||
[confsubst="$confsubst"])
|
||||
|
||||
AC_OUTPUT
|
||||
|
||||
echo ""
|
||||
echo ""
|
||||
echo "Configuration summary:"
|
||||
echo "----------------------"
|
||||
|
||||
if test x$have_libelf = xyes; then
|
||||
echo "DO HAVE libelf"
|
||||
else
|
||||
echo "DON'T HAVE libelf"
|
||||
fi
|
||||
|
||||
if test x$have_libusb = xyes; then
|
||||
echo "DO HAVE libusb"
|
||||
else
|
||||
echo "DON'T HAVE libusb"
|
||||
fi
|
||||
|
||||
if test x$have_libusb_1_0 = xyes; then
|
||||
if test x$enabled_libusb_1_0 = xyes; then
|
||||
echo "DO HAVE libusb_1_0"
|
||||
else
|
||||
echo "DISABLED libusb_1_0"
|
||||
fi
|
||||
else
|
||||
echo "DON'T HAVE libusb_1_0"
|
||||
fi
|
||||
|
||||
if test x$have_libftdi1 = xyes; then
|
||||
echo "DO HAVE libftdi1"
|
||||
else
|
||||
echo "DON'T HAVE libftdi1"
|
||||
fi
|
||||
|
||||
if test x$have_libftdi = xyes; then
|
||||
if test x$have_libftdi1 = xyes; then
|
||||
echo "DO HAVE libftdi (but prefer to use libftdi1)"
|
||||
else
|
||||
echo "DO HAVE libftdi"
|
||||
fi
|
||||
else
|
||||
echo "DON'T HAVE libftdi"
|
||||
fi
|
||||
|
||||
if test x$have_libhid = xyes; then
|
||||
echo "DO HAVE libhid"
|
||||
else
|
||||
echo "DON'T HAVE libhid"
|
||||
fi
|
||||
|
||||
if test x$have_libhidapi = xyes; then
|
||||
echo "DO HAVE libhidapi"
|
||||
else
|
||||
echo "DON'T HAVE libhidapi"
|
||||
fi
|
||||
|
||||
if test x$have_pthread = xyes; then
|
||||
echo "DO HAVE pthread"
|
||||
else
|
||||
echo "DON'T HAVE pthread"
|
||||
fi
|
||||
|
||||
if test x$enabled_doc = xyes; then
|
||||
echo "ENABLED doc"
|
||||
else
|
||||
echo "DISABLED doc"
|
||||
fi
|
||||
|
||||
if test x$enabled_parport = xyes; then
|
||||
echo "ENABLED parport"
|
||||
else
|
||||
echo "DISABLED parport"
|
||||
fi
|
||||
|
||||
if test x$enabled_linuxgpio = xyes; then
|
||||
echo "ENABLED linuxgpio"
|
||||
else
|
||||
echo "DISABLED linuxgpio"
|
||||
fi
|
||||
|
||||
if test x$enabled_linuxspi = xyes; then
|
||||
echo "ENABLED linuxspi"
|
||||
else
|
||||
echo "DISABLED linuxspi"
|
||||
fi
|
||||
|
||||
54
src/confwin.c
Normal file
54
src/confwin.c
Normal file
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
* avrdude - A Downloader/Uploader for AVR device programmers
|
||||
* Copyright (C) 2003-2004 Eric B. Weddington <eric@ecentral.com>
|
||||
*
|
||||
* 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
#include "avrdude.h"
|
||||
#include "libavrdude.h"
|
||||
|
||||
#if defined(WIN32NATIVE)
|
||||
|
||||
#include <limits.h>
|
||||
#include <windows.h>
|
||||
|
||||
|
||||
static char *filename;
|
||||
|
||||
|
||||
void win_sys_config_set(char sys_config[PATH_MAX])
|
||||
{
|
||||
sys_config[0] = 0;
|
||||
|
||||
/* Use Windows API call to search for the Windows default system config file.*/
|
||||
SearchPath(NULL, "avrdude.conf", NULL, PATH_MAX, sys_config, &filename);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
void win_usr_config_set(char usr_config[PATH_MAX])
|
||||
{
|
||||
usr_config[0] = 0;
|
||||
|
||||
/* Use Windows API call to search for the Windows default user config file. */
|
||||
SearchPath(NULL, "avrdude.rc", NULL, PATH_MAX, usr_config, &filename);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
83
src/crc16.c
Normal file
83
src/crc16.c
Normal file
@@ -0,0 +1,83 @@
|
||||
/*
|
||||
* Derived from CRC algorithm for JTAG ICE mkII, published in Atmel
|
||||
* Appnote AVR067. Converted from C++ to C.
|
||||
*/
|
||||
#include "crc16.h"
|
||||
|
||||
/* CRC16 Definitions */
|
||||
static const unsigned short crc_table[256] = {
|
||||
0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf,
|
||||
0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7,
|
||||
0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e,
|
||||
0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876,
|
||||
0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd,
|
||||
0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5,
|
||||
0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c,
|
||||
0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974,
|
||||
0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb,
|
||||
0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3,
|
||||
0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a,
|
||||
0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72,
|
||||
0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9,
|
||||
0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1,
|
||||
0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738,
|
||||
0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70,
|
||||
0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7,
|
||||
0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff,
|
||||
0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036,
|
||||
0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e,
|
||||
0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5,
|
||||
0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd,
|
||||
0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134,
|
||||
0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c,
|
||||
0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3,
|
||||
0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb,
|
||||
0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232,
|
||||
0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a,
|
||||
0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1,
|
||||
0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9,
|
||||
0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330,
|
||||
0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78
|
||||
};
|
||||
|
||||
/* CRC calculation macros */
|
||||
#define CRC_INIT 0xFFFF
|
||||
#define CRC(crcval,newchar) crcval = (crcval >> 8) ^ \
|
||||
crc_table[(crcval ^ newchar) & 0x00ff]
|
||||
|
||||
unsigned short
|
||||
crcsum(const unsigned char* message, unsigned long length,
|
||||
unsigned short crc)
|
||||
{
|
||||
unsigned long i;
|
||||
|
||||
for(i = 0; i < length; i++)
|
||||
{
|
||||
CRC(crc, message[i]);
|
||||
}
|
||||
return crc;
|
||||
}
|
||||
|
||||
int
|
||||
crcverify(const unsigned char* message, unsigned long length)
|
||||
{
|
||||
/*
|
||||
* Returns true if the last two bytes in a message is the crc of the
|
||||
* preceding bytes.
|
||||
*/
|
||||
unsigned short expected;
|
||||
|
||||
expected = crcsum(message, length - 2, CRC_INIT);
|
||||
return (expected & 0xff) == message[length - 2] &&
|
||||
((expected >> 8) & 0xff) == message[length - 1];
|
||||
}
|
||||
|
||||
void
|
||||
crcappend(unsigned char* message, unsigned long length)
|
||||
{
|
||||
unsigned long crc;
|
||||
|
||||
crc = crcsum(message, length, CRC_INIT);
|
||||
message[length] = (unsigned char)(crc & 0xff);
|
||||
message[length+1] = (unsigned char)((crc >> 8) & 0xff);
|
||||
}
|
||||
34
src/crc16.h
Normal file
34
src/crc16.h
Normal file
@@ -0,0 +1,34 @@
|
||||
#ifndef CRC16_H
|
||||
#define CRC16_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Derived from CRC algorithm for JTAG ICE mkII, published in Atmel
|
||||
* Appnote AVR067. Converted from C++ to C.
|
||||
*/
|
||||
|
||||
extern unsigned short crcsum(const unsigned char* message,
|
||||
unsigned long length,
|
||||
unsigned short crc);
|
||||
/*
|
||||
* Verify that the last two bytes is a (LSB first) valid CRC of the
|
||||
* message.
|
||||
*/
|
||||
extern int crcverify(const unsigned char* message,
|
||||
unsigned long length);
|
||||
/*
|
||||
* Append a two byte CRC (LSB first) to message. length is size of
|
||||
* message excluding crc. Space for the CRC bytes must be allocated
|
||||
* in advance!
|
||||
*/
|
||||
extern void crcappend(unsigned char* message,
|
||||
unsigned long length);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
516
src/dfu.c
Normal file
516
src/dfu.c
Normal file
@@ -0,0 +1,516 @@
|
||||
/*
|
||||
* avrdude - A Downloader/Uploader for AVR device programmers
|
||||
* Copyright (C) 2012 Kirill Levchenko
|
||||
*
|
||||
* 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/* $Id$ */
|
||||
|
||||
#include "ac_cfg.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <limits.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "avrdude.h"
|
||||
#include "libavrdude.h"
|
||||
|
||||
#include "dfu.h"
|
||||
|
||||
#include "usbdevs.h" /* for USB_VENDOR_ATMEL */
|
||||
|
||||
/* If we don't have LibUSB, define dummy functions that report an error. */
|
||||
|
||||
#ifndef HAVE_LIBUSB
|
||||
|
||||
struct dfu_dev *dfu_open(char *port_name) {
|
||||
avrdude_message(MSG_INFO, "%s: Error: No USB support in this compile of avrdude\n",
|
||||
progname);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int dfu_init(struct dfu_dev *dfu, unsigned short usb_vid, unsigned short usb_pid) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
void dfu_close(struct dfu_dev *dfu) {
|
||||
/* nothing */
|
||||
}
|
||||
|
||||
int dfu_getstatus(struct dfu_dev *dfu, struct dfu_status *status)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
int dfu_clrstatus(struct dfu_dev *dfu) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
int dfu_download(struct dfu_dev *dfu, void * ptr, int size) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
int dfu_upload(struct dfu_dev *dfu, void * ptr, int size) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
/* If we DO have LibUSB, we can define the real functions. */
|
||||
|
||||
/* DFU data structures and constants.
|
||||
*/
|
||||
|
||||
#define DFU_TIMEOUT 200 /* ms */
|
||||
|
||||
#define DFU_DNLOAD 1
|
||||
#define DFU_UPLOAD 2
|
||||
#define DFU_GETSTATUS 3
|
||||
#define DFU_CLRSTATUS 4
|
||||
#define DFU_GETSTATE 5 /* FLIPv1 only; not used */
|
||||
#define DFU_ABORT 6 /* FLIPv1 only */
|
||||
|
||||
/* Block counter global variable. Incremented each time a DFU_DNLOAD command
|
||||
* is sent to the device.
|
||||
*/
|
||||
|
||||
static uint16_t wIndex = 0;
|
||||
|
||||
/* INTERNAL FUNCTION PROTOTYPES
|
||||
*/
|
||||
|
||||
static char * get_usb_string(usb_dev_handle * dev_handle, int index);
|
||||
|
||||
/* EXPORTED FUNCTION DEFINITIONS
|
||||
*/
|
||||
|
||||
struct dfu_dev * dfu_open(char *port_spec)
|
||||
{
|
||||
struct dfu_dev *dfu;
|
||||
char *bus_name = NULL;
|
||||
char *dev_name = NULL;
|
||||
|
||||
/* The following USB device spec parsing code was copied from usbtiny.c. The
|
||||
* expected format is "usb:BUS:DEV" where BUS and DEV are the bus and device
|
||||
* names. We stash these away in the dfu_dev structure for the dfu_init()
|
||||
* function, where we actually open the device.
|
||||
*/
|
||||
|
||||
if (strncmp(port_spec, "usb", 3) != 0) {
|
||||
avrdude_message(MSG_INFO, "%s: Error: "
|
||||
"Invalid port specification \"%s\" for USB device\n",
|
||||
progname, port_spec);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if(':' == port_spec[3]) {
|
||||
bus_name = strdup(port_spec + 3 + 1);
|
||||
if (bus_name == NULL) {
|
||||
avrdude_message(MSG_INFO, "%s: Out of memory in strdup\n", progname);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
dev_name = strchr(bus_name, ':');
|
||||
if(NULL != dev_name)
|
||||
*dev_name++ = '\0';
|
||||
}
|
||||
|
||||
/* Allocate the dfu_dev structure and save the bus_name and dev_name
|
||||
* strings for use in dfu_initialize().
|
||||
*/
|
||||
|
||||
dfu = calloc(1, sizeof(struct dfu_dev));
|
||||
|
||||
if (dfu == NULL)
|
||||
{
|
||||
avrdude_message(MSG_INFO, "%s: out of memory\n", progname);
|
||||
free(bus_name);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
dfu->bus_name = bus_name;
|
||||
dfu->dev_name = dev_name;
|
||||
dfu->timeout = DFU_TIMEOUT;
|
||||
|
||||
/* LibUSB initialization. */
|
||||
|
||||
usb_init();
|
||||
usb_find_busses();
|
||||
usb_find_devices();
|
||||
|
||||
return dfu;
|
||||
}
|
||||
|
||||
int dfu_init(struct dfu_dev *dfu, unsigned short vid, unsigned short pid)
|
||||
{
|
||||
struct usb_device *found = NULL;
|
||||
struct usb_device *dev;
|
||||
struct usb_bus *bus;
|
||||
|
||||
/* At last, we reach out through the USB bus to the part. There are three
|
||||
* ways to specify the part: by USB address, by USB vendor and product id,
|
||||
* and by part name. To specify the part by USB address, the user specifies
|
||||
* a port parameter in the form "usb:BUS:DEV" (see dfu_open()). To specify
|
||||
* the part by vendor and product, the user must specify a usbvid and usbpid
|
||||
* in the configuration file. Finally, if the user specifies the part only,
|
||||
* we use the default vendor and product id.
|
||||
*/
|
||||
|
||||
if (pid == 0 && dfu->dev_name == NULL) {
|
||||
avrdude_message(MSG_INFO, "%s: Error: No DFU support for part; "
|
||||
"specify PID in config or USB address (via -P) to override.\n",
|
||||
progname);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Scan through all the devices for the part. The matching rules are:
|
||||
*
|
||||
* 1. If the user specified a USB bus name, it must match.
|
||||
* 2. If the user specified a USB device name, it must match.
|
||||
* 3. If the user didn't specify a USB device name and specified a vendor
|
||||
* id, the vendor id must match.
|
||||
* 4. If the user didn't specify a USB device name and specified a product
|
||||
* id, the product id must match.
|
||||
*/
|
||||
|
||||
for (bus = usb_busses; !found && bus != NULL; bus = bus->next) {
|
||||
for (dev = bus->devices; !found && dev != NULL; dev = dev->next) {
|
||||
if (dfu->bus_name != NULL && strcmp(bus->dirname, dfu->bus_name))
|
||||
continue;
|
||||
if (dfu->dev_name != NULL) {
|
||||
if (strcmp(dev->filename, dfu->dev_name))
|
||||
continue;
|
||||
} else if (vid != dev->descriptor.idVendor)
|
||||
continue;
|
||||
else if (pid != 0 && pid != dev->descriptor.idProduct)
|
||||
continue;
|
||||
|
||||
found = dev;
|
||||
}
|
||||
}
|
||||
|
||||
if (found == NULL) {
|
||||
/* We could try to be more informative here. For example, we could report
|
||||
* why the match failed, and if we came across another DFU-capable part.
|
||||
*/
|
||||
|
||||
avrdude_message(MSG_INFO, "%s: Error: No matching USB device found\n", progname);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(verbose)
|
||||
avrdude_message(MSG_INFO, "%s: Found VID=0x%04x PID=0x%04x at %s:%s\n",
|
||||
progname, found->descriptor.idVendor, found->descriptor.idProduct,
|
||||
found->bus->dirname, found->filename);
|
||||
|
||||
dfu->dev_handle = usb_open(found);
|
||||
|
||||
if (dfu->dev_handle == NULL) {
|
||||
avrdude_message(MSG_INFO, "%s: Error: USB device at %s:%s: %s\n",
|
||||
progname, found->bus->dirname, found->filename, usb_strerror());
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Save device, configuration, interface and endpoint descriptors. */
|
||||
|
||||
memcpy(&dfu->dev_desc, &found->descriptor, sizeof(dfu->dev_desc));
|
||||
memcpy(&dfu->conf_desc, found->config, sizeof(dfu->conf_desc));
|
||||
dfu->conf_desc.interface = NULL;
|
||||
|
||||
memcpy(&dfu->intf_desc, found->config->interface->altsetting,
|
||||
sizeof(dfu->intf_desc));
|
||||
dfu->intf_desc.endpoint = &dfu->endp_desc;
|
||||
|
||||
if (found->config->interface->altsetting->endpoint != 0)
|
||||
memcpy(&dfu->endp_desc, found->config->interface->altsetting->endpoint,
|
||||
sizeof(dfu->endp_desc));
|
||||
|
||||
/* Get strings. */
|
||||
|
||||
dfu->manf_str = get_usb_string(dfu->dev_handle,
|
||||
dfu->dev_desc.iManufacturer);
|
||||
|
||||
dfu->prod_str = get_usb_string(dfu->dev_handle,
|
||||
dfu->dev_desc.iProduct);
|
||||
|
||||
dfu->serno_str = get_usb_string(dfu->dev_handle,
|
||||
dfu->dev_desc.iSerialNumber);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void dfu_close(struct dfu_dev *dfu)
|
||||
{
|
||||
if (dfu->dev_handle != NULL)
|
||||
usb_close(dfu->dev_handle);
|
||||
if (dfu->bus_name != NULL)
|
||||
free(dfu->bus_name);
|
||||
if (dfu->manf_str != NULL)
|
||||
free(dfu->manf_str);
|
||||
if (dfu->prod_str != NULL)
|
||||
free(dfu->prod_str);
|
||||
if (dfu->serno_str != NULL)
|
||||
free(dfu->serno_str);
|
||||
}
|
||||
|
||||
int dfu_getstatus(struct dfu_dev *dfu, struct dfu_status *status)
|
||||
{
|
||||
int result;
|
||||
|
||||
avrdude_message(MSG_TRACE, "%s: dfu_getstatus(): issuing control IN message\n",
|
||||
progname);
|
||||
|
||||
result = usb_control_msg(dfu->dev_handle,
|
||||
0x80 | USB_TYPE_CLASS | USB_RECIP_INTERFACE, DFU_GETSTATUS, 0, 0,
|
||||
(char*) status, sizeof(struct dfu_status), dfu->timeout);
|
||||
|
||||
if (result < 0) {
|
||||
avrdude_message(MSG_INFO, "%s: Error: Failed to get DFU status: %s\n",
|
||||
progname, usb_strerror());
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (result < sizeof(struct dfu_status)) {
|
||||
avrdude_message(MSG_INFO, "%s: Error: Failed to get DFU status: %s\n",
|
||||
progname, "short read");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (result > sizeof(struct dfu_status)) {
|
||||
avrdude_message(MSG_INFO, "%s: Error: Oversize read (should not happen); "
|
||||
"exiting\n", progname);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
avrdude_message(MSG_TRACE, "%s: dfu_getstatus(): bStatus 0x%02x, bwPollTimeout %d, bState 0x%02x, iString %d\n",
|
||||
progname,
|
||||
status->bStatus,
|
||||
status->bwPollTimeout[0] | (status->bwPollTimeout[1] << 8) | (status->bwPollTimeout[2] << 16),
|
||||
status->bState,
|
||||
status->iString);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int dfu_clrstatus(struct dfu_dev *dfu)
|
||||
{
|
||||
int result;
|
||||
|
||||
avrdude_message(MSG_TRACE, "%s: dfu_clrstatus(): issuing control OUT message\n",
|
||||
progname);
|
||||
|
||||
result = usb_control_msg(dfu->dev_handle,
|
||||
USB_TYPE_CLASS | USB_RECIP_INTERFACE, DFU_CLRSTATUS, 0, 0,
|
||||
NULL, 0, dfu->timeout);
|
||||
|
||||
if (result < 0) {
|
||||
avrdude_message(MSG_INFO, "%s: Error: Failed to clear DFU status: %s\n",
|
||||
progname, usb_strerror());
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int dfu_abort(struct dfu_dev *dfu)
|
||||
{
|
||||
int result;
|
||||
|
||||
avrdude_message(MSG_TRACE, "%s: dfu_abort(): issuing control OUT message\n",
|
||||
progname);
|
||||
|
||||
result = usb_control_msg(dfu->dev_handle,
|
||||
USB_TYPE_CLASS | USB_RECIP_INTERFACE, DFU_ABORT, 0, 0,
|
||||
NULL, 0, dfu->timeout);
|
||||
|
||||
if (result < 0) {
|
||||
avrdude_message(MSG_INFO, "%s: Error: Failed to reset DFU state: %s\n",
|
||||
progname, usb_strerror());
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int dfu_dnload(struct dfu_dev *dfu, void *ptr, int size)
|
||||
{
|
||||
int result;
|
||||
|
||||
avrdude_message(MSG_TRACE, "%s: dfu_dnload(): issuing control OUT message, wIndex = %d, ptr = %p, size = %d\n",
|
||||
progname, wIndex, ptr, size);
|
||||
|
||||
result = usb_control_msg(dfu->dev_handle,
|
||||
USB_TYPE_CLASS | USB_RECIP_INTERFACE, DFU_DNLOAD, wIndex++, 0,
|
||||
ptr, size, dfu->timeout);
|
||||
|
||||
if (result < 0) {
|
||||
avrdude_message(MSG_INFO, "%s: Error: DFU_DNLOAD failed: %s\n",
|
||||
progname, usb_strerror());
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (result < size) {
|
||||
avrdude_message(MSG_INFO, "%s: Error: DFU_DNLOAD failed: %s\n",
|
||||
progname, "short write");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (result > size) {
|
||||
avrdude_message(MSG_INFO, "%s: Error: Oversize write (should not happen); " \
|
||||
"exiting\n", progname);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int dfu_upload(struct dfu_dev *dfu, void *ptr, int size)
|
||||
{
|
||||
int result;
|
||||
|
||||
avrdude_message(MSG_TRACE, "%s: dfu_upload(): issuing control IN message, wIndex = %d, ptr = %p, size = %d\n",
|
||||
progname, wIndex, ptr, size);
|
||||
|
||||
result = usb_control_msg(dfu->dev_handle,
|
||||
0x80 | USB_TYPE_CLASS | USB_RECIP_INTERFACE, DFU_UPLOAD, wIndex++, 0,
|
||||
ptr, size, dfu->timeout);
|
||||
|
||||
if (result < 0) {
|
||||
avrdude_message(MSG_INFO, "%s: Error: DFU_UPLOAD failed: %s\n",
|
||||
progname, usb_strerror());
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (result < size) {
|
||||
avrdude_message(MSG_INFO, "%s: Error: DFU_UPLOAD failed: %s\n",
|
||||
progname, "short read");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (result > size) {
|
||||
avrdude_message(MSG_INFO, "%s: Error: Oversize read (should not happen); "
|
||||
"exiting\n", progname);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void dfu_show_info(struct dfu_dev *dfu)
|
||||
{
|
||||
if (dfu->manf_str != NULL)
|
||||
avrdude_message(MSG_INFO, " USB Vendor : %s (0x%04hX)\n",
|
||||
dfu->manf_str, (unsigned short) dfu->dev_desc.idVendor);
|
||||
else
|
||||
avrdude_message(MSG_INFO, " USB Vendor : 0x%04hX\n",
|
||||
(unsigned short) dfu->dev_desc.idVendor);
|
||||
|
||||
if (dfu->prod_str != NULL)
|
||||
avrdude_message(MSG_INFO, " USB Product : %s (0x%04hX)\n",
|
||||
dfu->prod_str, (unsigned short) dfu->dev_desc.idProduct);
|
||||
else
|
||||
avrdude_message(MSG_INFO, " USB Product : 0x%04hX\n",
|
||||
(unsigned short) dfu->dev_desc.idProduct);
|
||||
|
||||
avrdude_message(MSG_INFO, " USB Release : %hu.%hu.%hu\n",
|
||||
((unsigned short) dfu->dev_desc.bcdDevice >> 8) & 0xFF,
|
||||
((unsigned short) dfu->dev_desc.bcdDevice >> 4) & 0xF,
|
||||
((unsigned short) dfu->dev_desc.bcdDevice >> 0) & 0xF);
|
||||
|
||||
if (dfu->serno_str != NULL)
|
||||
avrdude_message(MSG_INFO, " USB Serial No : %s\n", dfu->serno_str);
|
||||
}
|
||||
|
||||
/* INTERNAL FUNCTION DEFINITIONS
|
||||
*/
|
||||
|
||||
char * get_usb_string(usb_dev_handle * dev_handle, int index) {
|
||||
char buffer[256];
|
||||
char * str;
|
||||
int result;
|
||||
|
||||
if (index == 0)
|
||||
return NULL;
|
||||
|
||||
result = usb_get_string_simple(dev_handle, index, buffer, sizeof(buffer)-1);
|
||||
|
||||
if (result < 0) {
|
||||
avrdude_message(MSG_INFO, "%s: Warning: Failed to read USB device string %d: %s\n",
|
||||
progname, index, usb_strerror());
|
||||
return NULL;
|
||||
}
|
||||
|
||||
str = malloc(result+1);
|
||||
|
||||
if (str == NULL) {
|
||||
avrdude_message(MSG_INFO, "%s: Out of memory allocating a string\n", progname);
|
||||
return 0;
|
||||
}
|
||||
|
||||
memcpy(str, buffer, result);
|
||||
str[result] = '\0';
|
||||
return str;
|
||||
}
|
||||
|
||||
#endif /* defined(HAVE_LIBUSB) */
|
||||
|
||||
/* EXPORTED FUNCTIONS THAT DO NO REQUIRE LIBUSB
|
||||
*/
|
||||
|
||||
const char * dfu_status_str(int bStatus)
|
||||
{
|
||||
switch (bStatus) {
|
||||
case DFU_STATUS_OK: return "OK";
|
||||
case DFU_STATUS_ERR_TARGET: return "ERR_TARGET";
|
||||
case DFU_STATUS_ERR_FILE: return "ERR_FILE";
|
||||
case DFU_STATUS_ERR_WRITE: return "ERR_WRITE";
|
||||
case DFU_STATUS_ERR_ERASE: return "ERR_ERASE";
|
||||
case DFU_STATUS_ERR_CHECK_ERASED: return "ERR_CHECK_ERASED";
|
||||
case DFU_STATUS_ERR_PROG: return "ERR_PROG";
|
||||
case DFU_STATUS_ERR_VERIFY: return "ERR_VERIFY";
|
||||
case DFU_STATUS_ERR_ADDRESS: return "ERR_ADDRESS";
|
||||
case DFU_STATUS_ERR_NOTDONE: return "ERR_NOTDONE";
|
||||
case DFU_STATUS_ERR_FIRMWARE: return "ERR_FIRMWARE";
|
||||
case DFU_STATUS_ERR_VENDOR: return "ERR_VENDOR";
|
||||
case DFU_STATUS_ERR_USBR: return "ERR_USBR";
|
||||
case DFU_STATUS_ERR_POR: return "ERR_POR";
|
||||
case DFU_STATUS_ERR_UNKNOWN: return "ERR_UNKNOWN";
|
||||
case DFU_STATUS_ERR_STALLEDPKT: return "ERR_STALLEDPKT";
|
||||
default: return "Unknown";
|
||||
}
|
||||
}
|
||||
|
||||
const char * dfu_state_str(int bState)
|
||||
{
|
||||
switch (bState) {
|
||||
case DFU_STATE_APP_IDLE: return "APP_IDLE";
|
||||
case DFU_STATE_APP_DETACH: return "APP_DETACH";
|
||||
case DFU_STATE_DFU_IDLE: return "DFU_IDLE";
|
||||
case DFU_STATE_DFU_DLOAD_SYNC: return "DFU_DLOAD_SYNC";
|
||||
case DFU_STATE_DFU_DNBUSY: return "DFU_DNBUSY";
|
||||
case DFU_STATE_DFU_DNLOAD_IDLE: return "DFU_DNLOAD_IDLE";
|
||||
case DFU_STATE_DFU_MANIFEST_SYNC: return "DFU_MANIFEST_SYNC";
|
||||
case DFU_STATE_DFU_MANIFEST: return "DFU_MANIFEST";
|
||||
case DFU_STATE_DFU_MANIFEST_WAIT_RESET: return "DFU_MANIFEST_WAIT_RESET";
|
||||
case DFU_STATE_DFU_UPLOAD_IDLE: return "DFU_UPLOAD_IDLE";
|
||||
case DFU_STATE_DFU_ERROR: return "DFU_ERROR";
|
||||
default: return "Unknown";
|
||||
}
|
||||
}
|
||||
|
||||
137
src/dfu.h
Normal file
137
src/dfu.h
Normal file
@@ -0,0 +1,137 @@
|
||||
/*
|
||||
* avrdude - A Downloader/Uploader for AVR device programmers
|
||||
* Copyright (C) 2012 Kirill Levchenko
|
||||
*
|
||||
* 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/* $Id$ */
|
||||
|
||||
#ifndef dfu_h
|
||||
#define dfu_h
|
||||
|
||||
#include "ac_cfg.h"
|
||||
|
||||
#ifdef HAVE_LIBUSB
|
||||
#if defined(HAVE_USB_H)
|
||||
# include <usb.h>
|
||||
#elif defined(HAVE_LUSB0_USB_H)
|
||||
# include <lusb0_usb.h>
|
||||
#else
|
||||
# error "libusb needs either <usb.h> or <lusb0_usb.h>"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#include <limits.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* If we have LIBUSB, define the dfu_dev struct normally. Otherwise, declare
|
||||
* it as an empty struct so that code compiles, but we generate an error at
|
||||
* run time.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_LIBUSB
|
||||
|
||||
struct dfu_dev
|
||||
{
|
||||
char *bus_name, *dev_name;
|
||||
usb_dev_handle *dev_handle;
|
||||
struct usb_device_descriptor dev_desc;
|
||||
struct usb_config_descriptor conf_desc;
|
||||
struct usb_interface_descriptor intf_desc;
|
||||
struct usb_endpoint_descriptor endp_desc;
|
||||
char *manf_str, *prod_str, *serno_str;
|
||||
unsigned int timeout;
|
||||
};
|
||||
|
||||
#else
|
||||
|
||||
struct dfu_dev {
|
||||
// empty
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
/* We assume unsigned char is 1 byte. */
|
||||
|
||||
#if UCHAR_MAX != 255
|
||||
#error UCHAR_MAX != 255
|
||||
#endif
|
||||
|
||||
struct dfu_status {
|
||||
unsigned char bStatus;
|
||||
unsigned char bwPollTimeout[3];
|
||||
unsigned char bState;
|
||||
unsigned char iString;
|
||||
};
|
||||
|
||||
// Values of bStatus field.
|
||||
|
||||
#define DFU_STATUS_OK 0x0
|
||||
#define DFU_STATUS_ERR_TARGET 0x1
|
||||
#define DFU_STATUS_ERR_FILE 0x2
|
||||
#define DFU_STATUS_ERR_WRITE 0x3
|
||||
#define DFU_STATUS_ERR_ERASE 0x4
|
||||
#define DFU_STATUS_ERR_CHECK_ERASED 0x5
|
||||
#define DFU_STATUS_ERR_PROG 0x6
|
||||
#define DFU_STATUS_ERR_VERIFY 0x7
|
||||
#define DFU_STATUS_ERR_ADDRESS 0x8
|
||||
#define DFU_STATUS_ERR_NOTDONE 0x9
|
||||
#define DFU_STATUS_ERR_FIRMWARE 0xA
|
||||
#define DFU_STATUS_ERR_VENDOR 0xB
|
||||
#define DFU_STATUS_ERR_USBR 0xC
|
||||
#define DFU_STATUS_ERR_POR 0xD
|
||||
#define DFU_STATUS_ERR_UNKNOWN 0xE
|
||||
#define DFU_STATUS_ERR_STALLEDPKT 0xF
|
||||
|
||||
// Values of bState field.
|
||||
|
||||
#define DFU_STATE_APP_IDLE 0
|
||||
#define DFU_STATE_APP_DETACH 1
|
||||
#define DFU_STATE_DFU_IDLE 2
|
||||
#define DFU_STATE_DFU_DLOAD_SYNC 3
|
||||
#define DFU_STATE_DFU_DNBUSY 4
|
||||
#define DFU_STATE_DFU_DNLOAD_IDLE 5
|
||||
#define DFU_STATE_DFU_MANIFEST_SYNC 6
|
||||
#define DFU_STATE_DFU_MANIFEST 7
|
||||
#define DFU_STATE_DFU_MANIFEST_WAIT_RESET 8
|
||||
#define DFU_STATE_DFU_UPLOAD_IDLE 9
|
||||
#define DFU_STATE_DFU_ERROR 10
|
||||
|
||||
// FUNCTIONS
|
||||
|
||||
extern struct dfu_dev * dfu_open(char *port_spec);
|
||||
extern int dfu_init(struct dfu_dev *dfu,
|
||||
unsigned short vid, unsigned short pid);
|
||||
extern void dfu_close(struct dfu_dev *dfu);
|
||||
|
||||
extern int dfu_getstatus(struct dfu_dev *dfu, struct dfu_status *status);
|
||||
extern int dfu_clrstatus(struct dfu_dev *dfu);
|
||||
extern int dfu_dnload(struct dfu_dev *dfu, void *ptr, int size);
|
||||
extern int dfu_upload(struct dfu_dev *dfu, void *ptr, int size);
|
||||
extern int dfu_abort(struct dfu_dev *dfu);
|
||||
|
||||
extern void dfu_show_info(struct dfu_dev *dfu);
|
||||
|
||||
extern const char * dfu_status_str(int bStatus);
|
||||
extern const char * dfu_state_str(int bState);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* dfu_h */
|
||||
26
src/doc/.gitignore
vendored
Normal file
26
src/doc/.gitignore
vendored
Normal file
@@ -0,0 +1,26 @@
|
||||
avrdude.t2d/
|
||||
avrdude.t2p/
|
||||
Makefile
|
||||
Makefile.in
|
||||
avrdude-html
|
||||
avrdude.aux
|
||||
avrdude.cp
|
||||
avrdude.cps
|
||||
avrdude.dvi
|
||||
avrdude.fn
|
||||
avrdude.info
|
||||
avrdude.ky
|
||||
avrdude.log
|
||||
avrdude.pdf
|
||||
avrdude.pg
|
||||
avrdude.ps
|
||||
avrdude.toc
|
||||
avrdude.tp
|
||||
avrdude.vr
|
||||
mdate-sh
|
||||
stamp-vti
|
||||
texinfo.tex
|
||||
version.texi
|
||||
programmer_types.texi
|
||||
parts.texi
|
||||
programmers.texi
|
||||
94
src/doc/Makefile.am
Normal file
94
src/doc/Makefile.am
Normal file
@@ -0,0 +1,94 @@
|
||||
#
|
||||
# avrdude - A Downloader/Uploader for AVR device programmers
|
||||
# Copyright (C) 2003 Theodore A. Roth <troth@openavr.org>
|
||||
#
|
||||
# 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, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
|
||||
#
|
||||
# $Id$
|
||||
#
|
||||
|
||||
GENERATED_TEXINFOS = \
|
||||
$(builddir)/programmers.texi \
|
||||
$(builddir)/parts.texi \
|
||||
$(builddir)/programmer_types.texi \
|
||||
$(builddir)/version.texi
|
||||
|
||||
CLEANFILES = \
|
||||
$(GENERATED_TEXINFOS) \
|
||||
$(builddir)/stamp-vti
|
||||
|
||||
info_TEXINFOS = avrdude.texi
|
||||
|
||||
EXTRA_DIST = \
|
||||
parts_comments.txt
|
||||
|
||||
all-local: info html ps pdf
|
||||
|
||||
html: avrdude-html/avrdude.html
|
||||
|
||||
avrdude-html/avrdude.html: $(srcdir)/$(info_TEXINFOS) $(GENERATED_TEXINFOS)
|
||||
texi2html -split_node $(srcdir)/$(info_TEXINFOS)
|
||||
if [ -e ./avrdude.html -o -e ./avrdude_1.html ]; then \
|
||||
mkdir -p avrdude-html ; \
|
||||
mv -f *.html avrdude-html ; \
|
||||
else \
|
||||
mv -f avrdude avrdude-html; \
|
||||
fi;
|
||||
|
||||
$(builddir)/avrdude.info: $(GENERATED_TEXINFOS)
|
||||
$(builddir)/avrdude.dvi: $(GENERATED_TEXINFOS)
|
||||
$(builddir)/avrdude.pdf: $(GENERATED_TEXINFOS)
|
||||
|
||||
# if it does not exist make this first
|
||||
../avrdude$(EXEEXT):
|
||||
$(MAKE) -C .. avrdude$(EXEEXT)
|
||||
|
||||
$(builddir)/programmers.texi: ../avrdude$(EXEEXT) ../avrdude.conf Makefile
|
||||
../avrdude$(EXEEXT) -C ../avrdude.conf -c \? 2>&1 \
|
||||
| $(AWK) '$$2 ~ /^=$$/ {printf("@item @code{%s} @tab %s\n",$$1,gensub("[^=]+=[ \t]*","",1))}' \
|
||||
| sed "s# *,\? *<\?\(http://[^ \t>]*\)>\?#,@*\n@url{\1}#g" \
|
||||
>programmers.texi
|
||||
|
||||
$(builddir)/programmer_types.texi: ../avrdude$(EXEEXT) ../avrdude.conf Makefile
|
||||
../avrdude$(EXEEXT) -C ../avrdude.conf -c \?type 2>&1 \
|
||||
| $(AWK) '$$2 ~ /^=$$/ {printf("@item @code{%s} @tab %s\n",$$1,gensub("[^=]+=[ \t]*","",1))}' \
|
||||
| sed "s#<\?\(http://[^ \t,>]*\)>\?#@url{\1}#g" \
|
||||
>programmer_types.texi
|
||||
|
||||
$(builddir)/parts.texi: ../avrdude$(EXEEXT) ../avrdude.conf parts_comments.txt Makefile
|
||||
../avrdude$(EXEEXT) -C ../avrdude.conf -p \? 2>&1 \
|
||||
| $(AWK) '$$2 ~ /^=$$/ {printf("@item @code{%s} @tab %s\n",$$1,$$3)}' \
|
||||
| sed -e "`sed 's:\([^ \t]*\)[ \t]*\(.*\):s/\1$$/\1 \2/g:g' <parts_comments.txt`" \
|
||||
>parts.texi
|
||||
|
||||
clean-local:
|
||||
rm -rf avrdude-html *.info
|
||||
|
||||
install-data-local: install-docs
|
||||
|
||||
install-docs: html ps 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`; \
|
||||
for file in $$list; \
|
||||
do \
|
||||
$(INSTALL_DATA) $$file $(DOC_INST_DIR)/$$file; \
|
||||
done
|
||||
|
||||
uninstall-local:
|
||||
rm -rf $(DOC_INST_DIR)
|
||||
26
src/doc/TODO
Normal file
26
src/doc/TODO
Normal file
@@ -0,0 +1,26 @@
|
||||
|
||||
- Man page needs updated for avr910 info.
|
||||
|
||||
- Website needs to link to docs:
|
||||
http://savannah.nongnu.org/download/avrdude/doc/avrdude-html/
|
||||
|
||||
- Add "skip empty pages" optimization on avr910 paged write. The stk500 has
|
||||
this optimization already.
|
||||
|
||||
- Fix "overfull \hbox" issues in building documentation.
|
||||
|
||||
- FIXME: term.c: terminal_get_input(): strip newlines in non-readline input
|
||||
code.
|
||||
|
||||
- FIXME: avr910.c: avr910_cmd(): Insert version check here.
|
||||
|
||||
- FIXME: ser_posix.c: serial_close(): Should really restore the terminal to
|
||||
original state here.
|
||||
|
||||
- FIXME: main.c, par.c: exitspecs don't work if RESET-pin is controlled over
|
||||
PPICTRL.
|
||||
|
||||
- transfer ppi-speedtuning to the windows version (CAVEAT: This will make
|
||||
programming too fast for chips with 500kHz clock)
|
||||
|
||||
- make SCK-period configurable for PPI-programmers
|
||||
2598
src/doc/avrdude.texi
Normal file
2598
src/doc/avrdude.texi
Normal file
File diff suppressed because it is too large
Load Diff
5
src/doc/parts_comments.txt
Normal file
5
src/doc/parts_comments.txt
Normal file
@@ -0,0 +1,5 @@
|
||||
AT90S1200 (****)
|
||||
AT90S2343 (*)
|
||||
ATmega2560 (**)
|
||||
ATmega2561 (**)
|
||||
ATtiny11 (***)
|
||||
1606
src/fileio.c
Normal file
1606
src/fileio.c
Normal file
File diff suppressed because it is too large
Load Diff
949
src/flip1.c
Normal file
949
src/flip1.c
Normal file
@@ -0,0 +1,949 @@
|
||||
/*
|
||||
* avrdude - A Downloader/Uploader for AVR device programmers
|
||||
* Copyright (C) 2014 Joerg Wunsch
|
||||
*
|
||||
* This implementation has been cloned from FLIPv2 implementation
|
||||
* written by Kirill Levchenko.
|
||||
*
|
||||
* 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/* $Id$ */
|
||||
|
||||
#include "ac_cfg.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <limits.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#if HAVE_STDINT_H
|
||||
#include <stdint.h>
|
||||
#elif HAVE_INTTYPES_H
|
||||
#include <inttypes.h>
|
||||
#endif
|
||||
|
||||
|
||||
#include "avrdude.h"
|
||||
#include "libavrdude.h"
|
||||
|
||||
#include "flip1.h"
|
||||
#include "dfu.h"
|
||||
#include "usbdevs.h" /* for USB_VENDOR_ATMEL */
|
||||
|
||||
/* There are three versions of the FLIP protocol:
|
||||
*
|
||||
* Version 0: C51 parts
|
||||
* Version 1: megaAVR parts ("USB DFU Bootloader Datasheet" [doc7618])
|
||||
* Version 2: XMEGA parts (AVR4023 [doc8457])
|
||||
*
|
||||
* This implementation handles protocol version 1.
|
||||
*
|
||||
* Protocol version 1 has some, erm, "interesting" features:
|
||||
*
|
||||
* When contacting the fresh bootloader, the only allowed actions are
|
||||
* requesting the configuration/manufacturer information (which is
|
||||
* used to read the signature on AVRs), and to issue a "chip erase".
|
||||
* All operations on flash and EEPROM are restricted before a chip
|
||||
* erase has been seen (security protection).
|
||||
*
|
||||
* However, after the chip erase, the configuration/manufacturer
|
||||
* information can no longer be obtained ... they all respond with
|
||||
* 0xff. Essentially, the device needs a power cycle then, after
|
||||
* which the only actual command to access is a chip erase.
|
||||
*
|
||||
* Quite cumbersome to the user.
|
||||
*/
|
||||
|
||||
/* EXPORTED CONSTANT STRINGS */
|
||||
|
||||
const char flip1_desc[] = "FLIP USB DFU protocol version 1 (doc7618)";
|
||||
|
||||
/* PRIVATE DATA STRUCTURES */
|
||||
|
||||
struct flip1
|
||||
{
|
||||
struct dfu_dev *dfu;
|
||||
unsigned char part_sig[3];
|
||||
unsigned char part_rev;
|
||||
unsigned char boot_ver;
|
||||
unsigned char security_mode_flag; /* indicates the user has already
|
||||
* been hinted about security
|
||||
* mode */
|
||||
};
|
||||
|
||||
#define FLIP1(pgm) ((struct flip1 *)(pgm->cookie))
|
||||
|
||||
/* FLIP1 data structures and constants. */
|
||||
|
||||
struct flip1_cmd
|
||||
{
|
||||
unsigned char cmd;
|
||||
unsigned char args[5];
|
||||
};
|
||||
|
||||
struct flip1_cmd_header /* for memory read/write */
|
||||
{
|
||||
unsigned char cmd;
|
||||
unsigned char memtype;
|
||||
unsigned char start_addr[2];
|
||||
unsigned char end_addr[2];
|
||||
unsigned char padding[26];
|
||||
};
|
||||
|
||||
struct flip1_prog_footer
|
||||
{
|
||||
unsigned char crc[4]; /* not really used */
|
||||
unsigned char ftr_length; /* 0x10 */
|
||||
unsigned char signature[3]; /* "DFU" */
|
||||
unsigned char bcdversion[2]; /* 0x01, 0x10 */
|
||||
unsigned char vendor[2]; /* or 0xff, 0xff */
|
||||
unsigned char product[2]; /* or 0xff, 0xff */
|
||||
unsigned char device[2]; /* or 0xff, 0xff */
|
||||
};
|
||||
|
||||
#define FLIP1_CMD_PROG_START 0x01
|
||||
#define FLIP1_CMD_DISPLAY_DATA 0x03
|
||||
#define FLIP1_CMD_WRITE_COMMAND 0x04
|
||||
#define FLIP1_CMD_READ_COMMAND 0x05
|
||||
#define FLIP1_CMD_CHANGE_BASE_ADDRESS 0x06
|
||||
|
||||
/* args[1:0] for FLIP1_CMD_READ_COMMAND */
|
||||
#define FLIP1_READ_BOOTLOADER_VERSION { 0x00, 0x00 }
|
||||
#define FLIP1_READ_DEVICE_BOOT_ID1 { 0x00, 0x01 }
|
||||
#define FLIP1_READ_DEVICE_BOOT_ID2 { 0x00, 0x02 }
|
||||
#define FLIP1_READ_MANUFACTURER_CODE { 0x01, 0x30 }
|
||||
#define FLIP1_READ_FAMILY_CODE { 0x01, 0x31 }
|
||||
#define FLIP1_READ_PRODUCT_NAME { 0x01, 0x60 }
|
||||
#define FLIP1_READ_PRODUCT_REVISION { 0x01, 0x61 }
|
||||
|
||||
enum flip1_mem_unit {
|
||||
FLIP1_MEM_UNIT_FLASH = 0x00,
|
||||
FLIP1_MEM_UNIT_EEPROM = 0x01,
|
||||
FLIP1_MEM_UNIT_UNKNOWN = -1
|
||||
};
|
||||
|
||||
#define STATE_dfuERROR 10 /* bState; requires a DFU_CLRSTATUS */
|
||||
|
||||
#define LONG_DFU_TIMEOUT 10000 /* 10 s for program and erase */
|
||||
|
||||
/* EXPORTED PROGRAMMER FUNCTION PROTOTYPES */
|
||||
|
||||
static int flip1_open(PROGRAMMER *pgm, char *port_spec);
|
||||
static int flip1_initialize(PROGRAMMER* pgm, AVRPART *part);
|
||||
static void flip1_close(PROGRAMMER* pgm);
|
||||
static void flip1_enable(PROGRAMMER* pgm);
|
||||
static void flip1_disable(PROGRAMMER* pgm);
|
||||
static void flip1_display(PROGRAMMER* pgm, const char *prefix);
|
||||
static int flip1_program_enable(PROGRAMMER* pgm, AVRPART *part);
|
||||
static int flip1_chip_erase(PROGRAMMER* pgm, AVRPART *part);
|
||||
static int flip1_read_byte(PROGRAMMER* pgm, AVRPART *part, AVRMEM *mem,
|
||||
unsigned long addr, unsigned char *value);
|
||||
static int flip1_write_byte(PROGRAMMER* pgm, AVRPART *part, AVRMEM *mem,
|
||||
unsigned long addr, unsigned char value);
|
||||
static int flip1_paged_load(PROGRAMMER* pgm, AVRPART *part, AVRMEM *mem,
|
||||
unsigned int page_size, unsigned int addr, unsigned int n_bytes);
|
||||
static int flip1_paged_write(PROGRAMMER* pgm, AVRPART *part, AVRMEM *mem,
|
||||
unsigned int page_size, unsigned int addr, unsigned int n_bytes);
|
||||
static int flip1_read_sig_bytes(PROGRAMMER* pgm, AVRPART *part, AVRMEM *mem);
|
||||
static void flip1_setup(PROGRAMMER * pgm);
|
||||
static void flip1_teardown(PROGRAMMER * pgm);
|
||||
|
||||
/* INTERNAL PROGRAMMER FUNCTION PROTOTYPES */
|
||||
#ifdef HAVE_LIBUSB
|
||||
// The internal ones are made conditional, as they're not defined further down #ifndef HAVE_LIBUSB
|
||||
|
||||
static void flip1_show_info(struct flip1 *flip1);
|
||||
|
||||
static int flip1_read_memory(PROGRAMMER * pgm,
|
||||
enum flip1_mem_unit mem_unit, uint32_t addr, void *ptr, int size);
|
||||
static int flip1_write_memory(struct dfu_dev *dfu,
|
||||
enum flip1_mem_unit mem_unit, uint32_t addr, const void *ptr, int size);
|
||||
|
||||
static const char * flip1_status_str(const struct dfu_status *status);
|
||||
static const char * flip1_mem_unit_str(enum flip1_mem_unit mem_unit);
|
||||
static int flip1_set_mem_page(struct dfu_dev *dfu, unsigned short page_addr);
|
||||
static enum flip1_mem_unit flip1_mem_unit(const char *name);
|
||||
|
||||
#endif /* HAVE_LIBUSB */
|
||||
|
||||
/* THE INITPGM FUNCTION DEFINITIONS */
|
||||
|
||||
void flip1_initpgm(PROGRAMMER *pgm)
|
||||
{
|
||||
strcpy(pgm->type, "flip1");
|
||||
|
||||
/* Mandatory Functions */
|
||||
pgm->initialize = flip1_initialize;
|
||||
pgm->enable = flip1_enable;
|
||||
pgm->disable = flip1_disable;
|
||||
pgm->display = flip1_display;
|
||||
pgm->program_enable = flip1_program_enable;
|
||||
pgm->chip_erase = flip1_chip_erase;
|
||||
pgm->open = flip1_open;
|
||||
pgm->close = flip1_close;
|
||||
pgm->paged_load = flip1_paged_load;
|
||||
pgm->paged_write = flip1_paged_write;
|
||||
pgm->read_byte = flip1_read_byte;
|
||||
pgm->write_byte = flip1_write_byte;
|
||||
pgm->read_sig_bytes = flip1_read_sig_bytes;
|
||||
pgm->setup = flip1_setup;
|
||||
pgm->teardown = flip1_teardown;
|
||||
}
|
||||
|
||||
#ifdef HAVE_LIBUSB
|
||||
/* EXPORTED PROGRAMMER FUNCTION DEFINITIONS */
|
||||
|
||||
int flip1_open(PROGRAMMER *pgm, char *port_spec)
|
||||
{
|
||||
FLIP1(pgm)->dfu = dfu_open(port_spec);
|
||||
return (FLIP1(pgm)->dfu != NULL) ? 0 : -1;
|
||||
}
|
||||
|
||||
int flip1_initialize(PROGRAMMER* pgm, AVRPART *part)
|
||||
{
|
||||
unsigned short vid, pid;
|
||||
int result;
|
||||
struct dfu_dev *dfu = FLIP1(pgm)->dfu;
|
||||
|
||||
/* A note about return values. Negative return values from this function are
|
||||
* interpreted as failure by main(), from where this function is called.
|
||||
* However such failures are interpreted as a device signature check failure
|
||||
* and the user is adviced to use the -F option to override this check. In
|
||||
* our case, this is misleading, so we defer reporting an error until another
|
||||
* function is called. Thus, we always return 0 (success) from initialize().
|
||||
* I don't like this, but I don't want to mess with main().
|
||||
*/
|
||||
|
||||
/* The dfu_init() function will try to find the target part either based on
|
||||
* a USB address provided by the user with the -P option or by matching the
|
||||
* VID and PID of the device. The VID may be specified in the programmer
|
||||
* definition; if not specified, it defaults to USB_VENDOR_ATMEL (defined
|
||||
* in usbdevs.h). The PID may be specified either in the programmer
|
||||
* definition or the part definition; the programmer definition takes
|
||||
* priority. The default PID value is 0, which causes dfu_init() to ignore
|
||||
* the PID when matching a target device.
|
||||
*/
|
||||
|
||||
vid = (pgm->usbvid != 0) ? pgm->usbvid : USB_VENDOR_ATMEL;
|
||||
LNODEID usbpid = lfirst(pgm->usbpid);
|
||||
if (usbpid) {
|
||||
pid = *(int *)(ldata(usbpid));
|
||||
if (lnext(usbpid))
|
||||
avrdude_message(MSG_INFO, "%s: Warning: using PID 0x%04x, ignoring remaining PIDs in list\n",
|
||||
progname, pid);
|
||||
} else {
|
||||
pid = part->usbpid;
|
||||
}
|
||||
if (!ovsigck && (part->flags & AVRPART_HAS_PDI)) {
|
||||
avrdude_message(MSG_INFO, "%s: \"flip1\" (FLIP protocol version 1) is for AT90USB* and ATmega*U* devices.\n"
|
||||
"%s For Xmega devices, use \"flip2\".\n"
|
||||
"%s (Use -F to bypass this check.)\n",
|
||||
progname, progbuf, progbuf);
|
||||
return -1;
|
||||
}
|
||||
|
||||
result = dfu_init(FLIP1(pgm)->dfu, vid, pid);
|
||||
|
||||
if (result != 0)
|
||||
goto flip1_initialize_fail;
|
||||
|
||||
/* Check if descriptor values are what we expect. */
|
||||
|
||||
if (dfu->dev_desc.idVendor != vid)
|
||||
avrdude_message(MSG_INFO, "%s: Warning: USB idVendor = 0x%04X (expected 0x%04X)\n",
|
||||
progname, dfu->dev_desc.idVendor, vid);
|
||||
|
||||
if (pid != 0 && dfu->dev_desc.idProduct != pid)
|
||||
avrdude_message(MSG_INFO, "%s: Warning: USB idProduct = 0x%04X (expected 0x%04X)\n",
|
||||
progname, dfu->dev_desc.idProduct, pid);
|
||||
|
||||
if (dfu->dev_desc.bNumConfigurations != 1)
|
||||
avrdude_message(MSG_INFO, "%s: Warning: USB bNumConfigurations = %d (expected 1)\n",
|
||||
progname, (int) dfu->dev_desc.bNumConfigurations);
|
||||
|
||||
if (dfu->conf_desc.bNumInterfaces != 1)
|
||||
avrdude_message(MSG_INFO, "%s: Warning: USB bNumInterfaces = %d (expected 1)\n",
|
||||
progname, (int) dfu->conf_desc.bNumInterfaces);
|
||||
|
||||
if (dfu->dev_desc.bDeviceClass != 254)
|
||||
avrdude_message(MSG_INFO, "%s: Warning: USB bDeviceClass = %d (expected 254)\n",
|
||||
progname, (int) dfu->dev_desc.bDeviceClass);
|
||||
|
||||
if (dfu->dev_desc.bDeviceSubClass != 1)
|
||||
avrdude_message(MSG_INFO, "%s: Warning: USB bDeviceSubClass = %d (expected 1)\n",
|
||||
progname, (int) dfu->dev_desc.bDeviceSubClass);
|
||||
|
||||
if (dfu->dev_desc.bDeviceProtocol != 0)
|
||||
avrdude_message(MSG_INFO, "%s: Warning: USB bDeviceProtocol = %d (expected 0)\n",
|
||||
progname, (int) dfu->dev_desc.bDeviceProtocol);
|
||||
|
||||
/*
|
||||
* doc7618 claims an interface class of FEh and a subclas 01h.
|
||||
* However, as of today (2014-01-16), all values in the interface
|
||||
* descriptor (except of bLength and bDescriptorType) are actually
|
||||
* 0. So rather don't check these.
|
||||
*/
|
||||
if (0) {
|
||||
if (dfu->intf_desc.bInterfaceClass != 254)
|
||||
avrdude_message(MSG_INFO, "%s: Warning: USB bInterfaceClass = %d (expected 254)\n",
|
||||
progname, (int) dfu->intf_desc.bInterfaceClass);
|
||||
|
||||
if (dfu->intf_desc.bInterfaceSubClass != 1)
|
||||
avrdude_message(MSG_INFO, "%s: Warning: USB bInterfaceSubClass = %d (expected 1)\n",
|
||||
progname, (int) dfu->intf_desc.bInterfaceSubClass);
|
||||
|
||||
if (dfu->intf_desc.bInterfaceProtocol != 0)
|
||||
avrdude_message(MSG_INFO, "%s: Warning: USB bInterfaceSubClass = %d (expected 0)\n",
|
||||
progname, (int) dfu->intf_desc.bInterfaceProtocol);
|
||||
}
|
||||
|
||||
if (dfu->dev_desc.bMaxPacketSize0 != 32)
|
||||
avrdude_message(MSG_INFO, "%s: Warning: bMaxPacketSize0 (%d) != 32, things might go wrong\n",
|
||||
progname, dfu->dev_desc.bMaxPacketSize0);
|
||||
|
||||
if (verbose)
|
||||
flip1_show_info(FLIP1(pgm));
|
||||
|
||||
dfu_abort(dfu);
|
||||
|
||||
return 0;
|
||||
|
||||
flip1_initialize_fail:
|
||||
dfu_close(FLIP1(pgm)->dfu);
|
||||
FLIP1(pgm)->dfu = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void flip1_close(PROGRAMMER* pgm)
|
||||
{
|
||||
if (FLIP1(pgm)->dfu != NULL) {
|
||||
dfu_close(FLIP1(pgm)->dfu);
|
||||
FLIP1(pgm)->dfu = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void flip1_enable(PROGRAMMER* pgm)
|
||||
{
|
||||
/* Nothing to do. */
|
||||
}
|
||||
|
||||
void flip1_disable(PROGRAMMER* pgm)
|
||||
{
|
||||
/* Nothing to do. */
|
||||
}
|
||||
|
||||
void flip1_display(PROGRAMMER* pgm, const char *prefix)
|
||||
{
|
||||
/* Nothing to do. */
|
||||
}
|
||||
|
||||
int flip1_program_enable(PROGRAMMER* pgm, AVRPART *part)
|
||||
{
|
||||
/* I couldn't find anything that uses this function, although it is marked
|
||||
* as "mandatory" in pgm.c. In case anyone does use it, we'll report an
|
||||
* error if we failed to initialize.
|
||||
*/
|
||||
|
||||
return (FLIP1(pgm)->dfu != NULL) ? 0 : -1;
|
||||
}
|
||||
|
||||
int flip1_chip_erase(PROGRAMMER* pgm, AVRPART *part)
|
||||
{
|
||||
struct dfu_status status;
|
||||
int cmd_result = 0;
|
||||
int aux_result;
|
||||
unsigned int default_timeout = FLIP1(pgm)->dfu->timeout;
|
||||
|
||||
avrdude_message(MSG_NOTICE2, "%s: flip_chip_erase()\n", progname);
|
||||
|
||||
struct flip1_cmd cmd = {
|
||||
FLIP1_CMD_WRITE_COMMAND, { 0, 0xff }
|
||||
};
|
||||
|
||||
FLIP1(pgm)->dfu->timeout = LONG_DFU_TIMEOUT;
|
||||
cmd_result = dfu_dnload(FLIP1(pgm)->dfu, &cmd, 3);
|
||||
aux_result = dfu_getstatus(FLIP1(pgm)->dfu, &status);
|
||||
FLIP1(pgm)->dfu->timeout = default_timeout;
|
||||
|
||||
if (cmd_result < 0 || aux_result < 0)
|
||||
return -1;
|
||||
|
||||
if (status.bStatus != DFU_STATUS_OK) {
|
||||
avrdude_message(MSG_INFO, "%s: failed to send chip erase command: %s\n",
|
||||
progname, flip1_status_str(&status));
|
||||
if (status.bState == STATE_dfuERROR)
|
||||
dfu_clrstatus(FLIP1(pgm)->dfu);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int flip1_read_byte(PROGRAMMER* pgm, AVRPART *part, AVRMEM *mem,
|
||||
unsigned long addr, unsigned char *value)
|
||||
{
|
||||
enum flip1_mem_unit mem_unit;
|
||||
|
||||
if (FLIP1(pgm)->dfu == NULL)
|
||||
return -1;
|
||||
|
||||
if (strcasecmp(mem->desc, "signature") == 0) {
|
||||
if (flip1_read_sig_bytes(pgm, part, mem) < 0)
|
||||
return -1;
|
||||
if (addr > mem->size) {
|
||||
avrdude_message(MSG_INFO, "%s: flip1_read_byte(signature): address %lu out of range\n",
|
||||
progname, addr);
|
||||
return -1;
|
||||
}
|
||||
*value = mem->buf[addr];
|
||||
return 0;
|
||||
}
|
||||
|
||||
mem_unit = flip1_mem_unit(mem->desc);
|
||||
|
||||
if (mem_unit == FLIP1_MEM_UNIT_UNKNOWN) {
|
||||
avrdude_message(MSG_INFO, "%s: Error: "
|
||||
"\"%s\" memory not accessible using FLIP",
|
||||
progname, mem->desc);
|
||||
avrdude_message(MSG_INFO, "\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (mem_unit == FLIP1_MEM_UNIT_EEPROM)
|
||||
/* 0x01 is used for blank check when reading, 0x02 is EEPROM */
|
||||
mem_unit = 2;
|
||||
|
||||
return flip1_read_memory(pgm, mem_unit, addr, value, 1);
|
||||
}
|
||||
|
||||
int flip1_write_byte(PROGRAMMER* pgm, AVRPART *part, AVRMEM *mem,
|
||||
unsigned long addr, unsigned char value)
|
||||
{
|
||||
enum flip1_mem_unit mem_unit;
|
||||
|
||||
if (FLIP1(pgm)->dfu == NULL)
|
||||
return -1;
|
||||
|
||||
mem_unit = flip1_mem_unit(mem->desc);
|
||||
|
||||
if (mem_unit == FLIP1_MEM_UNIT_UNKNOWN) {
|
||||
avrdude_message(MSG_INFO, "%s: Error: "
|
||||
"\"%s\" memory not accessible using FLIP",
|
||||
progname, mem->desc);
|
||||
avrdude_message(MSG_INFO, "\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return flip1_write_memory(FLIP1(pgm)->dfu, mem_unit, addr, &value, 1);
|
||||
}
|
||||
|
||||
int flip1_paged_load(PROGRAMMER* pgm, AVRPART *part, AVRMEM *mem,
|
||||
unsigned int page_size, unsigned int addr, unsigned int n_bytes)
|
||||
{
|
||||
enum flip1_mem_unit mem_unit;
|
||||
|
||||
if (FLIP1(pgm)->dfu == NULL)
|
||||
return -1;
|
||||
|
||||
mem_unit = flip1_mem_unit(mem->desc);
|
||||
|
||||
if (mem_unit == FLIP1_MEM_UNIT_UNKNOWN) {
|
||||
avrdude_message(MSG_INFO, "%s: Error: "
|
||||
"\"%s\" memory not accessible using FLIP",
|
||||
progname, mem->desc);
|
||||
avrdude_message(MSG_INFO, "\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (mem_unit == FLIP1_MEM_UNIT_EEPROM)
|
||||
/* 0x01 is used for blank check when reading, 0x02 is EEPROM */
|
||||
mem_unit = 2;
|
||||
|
||||
return flip1_read_memory(pgm, mem_unit, addr, mem->buf + addr, n_bytes);
|
||||
}
|
||||
|
||||
int flip1_paged_write(PROGRAMMER* pgm, AVRPART *part, AVRMEM *mem,
|
||||
unsigned int page_size, unsigned int addr, unsigned int n_bytes)
|
||||
{
|
||||
enum flip1_mem_unit mem_unit;
|
||||
int result;
|
||||
|
||||
if (FLIP1(pgm)->dfu == NULL)
|
||||
return -1;
|
||||
|
||||
mem_unit = flip1_mem_unit(mem->desc);
|
||||
|
||||
if (mem_unit == FLIP1_MEM_UNIT_UNKNOWN) {
|
||||
avrdude_message(MSG_INFO, "%s: Error: "
|
||||
"\"%s\" memory not accessible using FLIP",
|
||||
progname, mem->desc);
|
||||
avrdude_message(MSG_INFO, "\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (n_bytes > INT_MAX) {
|
||||
/* This should never happen, unless the int type is only 16 bits. */
|
||||
avrdude_message(MSG_INFO, "%s: Error: Attempting to read more than %d bytes\n",
|
||||
progname, INT_MAX);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
result = flip1_write_memory(FLIP1(pgm)->dfu, mem_unit, addr,
|
||||
mem->buf + addr, n_bytes);
|
||||
|
||||
return (result == 0) ? n_bytes : -1;
|
||||
}
|
||||
|
||||
int flip1_read_sig_bytes(PROGRAMMER* pgm, AVRPART *part, AVRMEM *mem)
|
||||
{
|
||||
avrdude_message(MSG_NOTICE2, "%s: flip1_read_sig_bytes(): ", progname);
|
||||
|
||||
if (FLIP1(pgm)->dfu == NULL)
|
||||
return -1;
|
||||
|
||||
if (mem->size < sizeof(FLIP1(pgm)->part_sig)) {
|
||||
avrdude_message(MSG_INFO, "%s: Error: Signature read must be at least %u bytes\n",
|
||||
progname, (unsigned int) sizeof(FLIP1(pgm)->part_sig));
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (FLIP1(pgm)->part_sig[0] == 0 &&
|
||||
FLIP1(pgm)->part_sig[1] == 0 &&
|
||||
FLIP1(pgm)->part_sig[2] == 0)
|
||||
{
|
||||
/* signature not yet cached */
|
||||
struct dfu_status status;
|
||||
int cmd_result = 0;
|
||||
int aux_result;
|
||||
int i;
|
||||
struct flip1_cmd cmd = {
|
||||
FLIP1_CMD_READ_COMMAND, FLIP1_READ_FAMILY_CODE
|
||||
};
|
||||
|
||||
avrdude_message(MSG_NOTICE2, "from device\n");
|
||||
|
||||
for (i = 0; i < 3; i++)
|
||||
{
|
||||
if (i == 1)
|
||||
cmd.args[1] = 0x60; /* product name */
|
||||
else if (i == 2)
|
||||
cmd.args[1] = 0x61; /* product revision */
|
||||
|
||||
cmd_result = dfu_dnload(FLIP1(pgm)->dfu, &cmd, 3);
|
||||
aux_result = dfu_getstatus(FLIP1(pgm)->dfu, &status);
|
||||
|
||||
if (cmd_result < 0 || aux_result < 0)
|
||||
return -1;
|
||||
|
||||
if (status.bStatus != DFU_STATUS_OK)
|
||||
{
|
||||
avrdude_message(MSG_INFO, "%s: failed to send cmd for signature byte %d: %s\n",
|
||||
progname, i, flip1_status_str(&status));
|
||||
if (status.bState == STATE_dfuERROR)
|
||||
dfu_clrstatus(FLIP1(pgm)->dfu);
|
||||
return -1;
|
||||
}
|
||||
|
||||
cmd_result = dfu_upload(FLIP1(pgm)->dfu, &(FLIP1(pgm)->part_sig[i]), 1);
|
||||
aux_result = dfu_getstatus(FLIP1(pgm)->dfu, &status);
|
||||
|
||||
if (cmd_result < 0 || aux_result < 0)
|
||||
return -1;
|
||||
|
||||
if (status.bStatus != DFU_STATUS_OK)
|
||||
{
|
||||
avrdude_message(MSG_INFO, "%s: failed to read signature byte %d: %s\n",
|
||||
progname, i, flip1_status_str(&status));
|
||||
if (status.bState == STATE_dfuERROR)
|
||||
dfu_clrstatus(FLIP1(pgm)->dfu);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
avrdude_message(MSG_NOTICE2, "cached\n");
|
||||
}
|
||||
|
||||
memcpy(mem->buf, FLIP1(pgm)->part_sig, sizeof(FLIP1(pgm)->part_sig));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void flip1_setup(PROGRAMMER * pgm)
|
||||
{
|
||||
pgm->cookie = calloc(1, sizeof(struct flip1));
|
||||
|
||||
if (pgm->cookie == NULL) {
|
||||
avrdude_message(MSG_INFO, "%s: Out of memory allocating private data structure\n",
|
||||
progname);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
void flip1_teardown(PROGRAMMER * pgm)
|
||||
{
|
||||
free(pgm->cookie);
|
||||
pgm->cookie = NULL;
|
||||
}
|
||||
|
||||
/* INTERNAL FUNCTION DEFINITIONS
|
||||
*/
|
||||
|
||||
void flip1_show_info(struct flip1 *flip1)
|
||||
{
|
||||
dfu_show_info(flip1->dfu);
|
||||
avrdude_message(MSG_INFO, " USB max packet size : %hu\n",
|
||||
(unsigned short) flip1->dfu->dev_desc.bMaxPacketSize0);
|
||||
}
|
||||
|
||||
int flip1_read_memory(PROGRAMMER * pgm,
|
||||
enum flip1_mem_unit mem_unit, uint32_t addr, void *ptr, int size)
|
||||
{
|
||||
struct dfu_dev *dfu = FLIP1(pgm)->dfu;
|
||||
unsigned short page_addr;
|
||||
struct dfu_status status;
|
||||
int cmd_result = 0;
|
||||
int aux_result;
|
||||
struct flip1_cmd cmd = {
|
||||
FLIP1_CMD_DISPLAY_DATA, { mem_unit }
|
||||
};
|
||||
unsigned int default_timeout = dfu->timeout;
|
||||
|
||||
|
||||
avrdude_message(MSG_NOTICE2, "%s: flip_read_memory(%s, 0x%04x, %d)\n",
|
||||
progname, flip1_mem_unit_str(mem_unit), addr, size);
|
||||
|
||||
/*
|
||||
* As this function is called once per page, no need to handle 64
|
||||
* KiB border crossing below.
|
||||
*
|
||||
* Also, on AVRs, no page size is larger than 1 KiB, so no need to
|
||||
* split the request into multiple 1 KiB chunks.
|
||||
*/
|
||||
if (mem_unit == FLIP1_MEM_UNIT_FLASH) {
|
||||
page_addr = addr >> 16;
|
||||
if (flip1_set_mem_page(dfu, page_addr) < 0)
|
||||
return -1;
|
||||
}
|
||||
|
||||
cmd.args[1] = (addr >> 8) & 0xFF;
|
||||
cmd.args[2] = addr & 0xFF;
|
||||
cmd.args[3] = ((addr + size - 1) >> 8) & 0xFF;
|
||||
cmd.args[4] = (addr + size - 1) & 0xFF;
|
||||
|
||||
dfu->timeout = LONG_DFU_TIMEOUT;
|
||||
cmd_result = dfu_dnload(dfu, &cmd, 6);
|
||||
dfu->timeout = default_timeout;
|
||||
aux_result = dfu_getstatus(dfu, &status);
|
||||
|
||||
if (cmd_result < 0 || aux_result < 0)
|
||||
return -1;
|
||||
|
||||
if (status.bStatus != DFU_STATUS_OK)
|
||||
{
|
||||
avrdude_message(MSG_INFO, "%s: failed to read %u bytes of %s memory @%u: %s\n",
|
||||
progname, size, flip1_mem_unit_str(mem_unit), addr,
|
||||
flip1_status_str(&status));
|
||||
if (status.bState == STATE_dfuERROR)
|
||||
dfu_clrstatus(dfu);
|
||||
return -1;
|
||||
}
|
||||
|
||||
cmd_result = dfu_upload(dfu, (char*) ptr, size);
|
||||
aux_result = dfu_getstatus(dfu, &status);
|
||||
|
||||
if (cmd_result < 0 && aux_result == 0 &&
|
||||
status.bStatus == DFU_STATUS_ERR_WRITE) {
|
||||
if (FLIP1(pgm)->security_mode_flag == 0)
|
||||
avrdude_message(MSG_INFO, "\n%s:\n"
|
||||
"%s***********************************************************************\n"
|
||||
"%sMaybe the device is in ``security mode´´, and needs a chip erase first?\n"
|
||||
"%s***********************************************************************\n"
|
||||
"\n",
|
||||
progname, progbuf, progbuf, progbuf);
|
||||
FLIP1(pgm)->security_mode_flag = 1;
|
||||
}
|
||||
|
||||
if (cmd_result < 0 || aux_result < 0)
|
||||
return -1;
|
||||
|
||||
if (status.bStatus != DFU_STATUS_OK)
|
||||
{
|
||||
avrdude_message(MSG_INFO, "%s: failed to read %u bytes of %s memory @%u: %s\n",
|
||||
progname, size, flip1_mem_unit_str(mem_unit), addr,
|
||||
flip1_status_str(&status));
|
||||
if (status.bState == STATE_dfuERROR)
|
||||
dfu_clrstatus(dfu);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int flip1_write_memory(struct dfu_dev *dfu,
|
||||
enum flip1_mem_unit mem_unit, uint32_t addr, const void *ptr, int size)
|
||||
{
|
||||
unsigned short page_addr;
|
||||
int write_size;
|
||||
struct dfu_status status;
|
||||
int cmd_result = 0;
|
||||
int aux_result;
|
||||
struct flip1_cmd_header cmd_header = {
|
||||
FLIP1_CMD_PROG_START, mem_unit
|
||||
};
|
||||
struct flip1_prog_footer cmd_footer = {
|
||||
{ 0, 0, 0, 0 }, /* CRC */
|
||||
0x10, /* footer length */
|
||||
{ 'D', 'F', 'U' }, /* signature */
|
||||
{ 0x01, 0x10 }, /* BCD version */
|
||||
{ 0xff, 0xff }, /* vendor */
|
||||
{ 0xff, 0xff }, /* product */
|
||||
{ 0xff, 0xff } /* device */
|
||||
};
|
||||
unsigned int default_timeout = dfu->timeout;
|
||||
unsigned char *buf;
|
||||
|
||||
avrdude_message(MSG_NOTICE2, "%s: flip_write_memory(%s, 0x%04x, %d)\n",
|
||||
progname, flip1_mem_unit_str(mem_unit), addr, size);
|
||||
|
||||
if (size < 32) {
|
||||
/* presumably single-byte updates; must be padded to USB endpoint size */
|
||||
if ((addr + size - 1) / 32 != addr / 32) {
|
||||
avrdude_message(MSG_INFO, "%s: flip_write_memory(): begin (0x%x) and end (0x%x) not within same 32-byte block\n",
|
||||
progname, addr, addr + size - 1);
|
||||
return -1;
|
||||
}
|
||||
write_size = 32;
|
||||
} else {
|
||||
write_size = size;
|
||||
}
|
||||
|
||||
if ((buf = malloc(sizeof(struct flip1_cmd_header) +
|
||||
write_size +
|
||||
sizeof(struct flip1_prog_footer))) == 0) {
|
||||
avrdude_message(MSG_INFO, "%s: Out of memory\n", progname);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* As this function is called once per page, no need to handle 64
|
||||
* KiB border crossing below.
|
||||
*
|
||||
* Also, on AVRs, no page size is larger than 1 KiB, so no need to
|
||||
* split the request into multiple 1 KiB chunks.
|
||||
*/
|
||||
if (mem_unit == FLIP1_MEM_UNIT_FLASH) {
|
||||
page_addr = addr >> 16;
|
||||
if (flip1_set_mem_page(dfu, page_addr) < 0) {
|
||||
free(buf);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
cmd_header.start_addr[0] = (addr >> 8) & 0xFF;
|
||||
cmd_header.start_addr[1] = addr & 0xFF;
|
||||
cmd_header.end_addr[0] = ((addr + size - 1) >> 8) & 0xFF;
|
||||
cmd_header.end_addr[1] = (addr + size - 1) & 0xFF;
|
||||
|
||||
memcpy(buf, &cmd_header, sizeof(struct flip1_cmd_header));
|
||||
if (size < 32) {
|
||||
memset(buf + sizeof(struct flip1_cmd_header), 0xff, 32);
|
||||
memcpy(buf + sizeof(struct flip1_cmd_header) + (addr % 32), ptr, size);
|
||||
} else {
|
||||
memcpy(buf + sizeof(struct flip1_cmd_header), ptr, size);
|
||||
}
|
||||
memcpy(buf + sizeof(struct flip1_cmd_header) + write_size,
|
||||
&cmd_footer, sizeof(struct flip1_prog_footer));
|
||||
|
||||
dfu->timeout = LONG_DFU_TIMEOUT;
|
||||
cmd_result = dfu_dnload(dfu, buf,
|
||||
sizeof(struct flip1_cmd_header) +
|
||||
write_size +
|
||||
sizeof(struct flip1_prog_footer));
|
||||
aux_result = dfu_getstatus(dfu, &status);
|
||||
dfu->timeout = default_timeout;
|
||||
|
||||
free(buf);
|
||||
|
||||
if (aux_result < 0 || cmd_result < 0)
|
||||
return -1;
|
||||
|
||||
if (status.bStatus != DFU_STATUS_OK)
|
||||
{
|
||||
avrdude_message(MSG_INFO, "%s: failed to write %u bytes of %s memory @%u: %s\n",
|
||||
progname, size, flip1_mem_unit_str(mem_unit), addr,
|
||||
flip1_status_str(&status));
|
||||
if (status.bState == STATE_dfuERROR)
|
||||
dfu_clrstatus(dfu);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int flip1_set_mem_page(struct dfu_dev *dfu,
|
||||
unsigned short page_addr)
|
||||
{
|
||||
struct dfu_status status;
|
||||
int cmd_result = 0;
|
||||
int aux_result;
|
||||
|
||||
struct flip1_cmd cmd = {
|
||||
FLIP1_CMD_CHANGE_BASE_ADDRESS, { 0, page_addr }
|
||||
};
|
||||
|
||||
cmd_result = dfu_dnload(dfu, &cmd, 3);
|
||||
|
||||
aux_result = dfu_getstatus(dfu, &status);
|
||||
|
||||
if (cmd_result < 0 || aux_result < 0)
|
||||
return -1;
|
||||
|
||||
if (status.bStatus != DFU_STATUS_OK)
|
||||
{
|
||||
avrdude_message(MSG_INFO, "%s: failed to set memory page: %s\n",
|
||||
progname, flip1_status_str(&status));
|
||||
if (status.bState == STATE_dfuERROR)
|
||||
dfu_clrstatus(dfu);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
const char * flip1_status_str(const struct dfu_status *status)
|
||||
{
|
||||
static const char *msg[] = {
|
||||
"No error condition is present",
|
||||
"File is not targeted for use by this device",
|
||||
"File is for this device but fails some vendor-specific verification test",
|
||||
"Device id unable to write memory",
|
||||
"Memory erase function failed",
|
||||
"Memory erase check failed",
|
||||
"Program memory function failed",
|
||||
"Programmed memory failed verification",
|
||||
"Cannot program memory due to received address that is out of range",
|
||||
"Received DFU_DNLOAD with wLength = 0, but device does not think it has all the data yet.",
|
||||
"Device's firmware is corrupted. It cannot return to run-time operations",
|
||||
"iString indicates a vendor-specific error",
|
||||
"Device detected unexpected USB reset signaling",
|
||||
"Device detected unexpected power on reset",
|
||||
"Something went wrong, but the device does not know what it was",
|
||||
"Device stalled an unexpected request",
|
||||
};
|
||||
if (status->bStatus < sizeof msg / sizeof msg[0])
|
||||
return msg[status->bStatus];
|
||||
|
||||
return "Unknown status code";
|
||||
}
|
||||
|
||||
const char * flip1_mem_unit_str(enum flip1_mem_unit mem_unit)
|
||||
{
|
||||
switch (mem_unit) {
|
||||
case FLIP1_MEM_UNIT_FLASH: return "Flash";
|
||||
case FLIP1_MEM_UNIT_EEPROM: return "EEPROM";
|
||||
default: return "unknown";
|
||||
}
|
||||
}
|
||||
|
||||
enum flip1_mem_unit flip1_mem_unit(const char *name) {
|
||||
if (strcasecmp(name, "flash") == 0)
|
||||
return FLIP1_MEM_UNIT_FLASH;
|
||||
if (strcasecmp(name, "eeprom") == 0)
|
||||
return FLIP1_MEM_UNIT_EEPROM;
|
||||
return FLIP1_MEM_UNIT_UNKNOWN;
|
||||
}
|
||||
#else /* HAVE_LIBUSB */
|
||||
// Dummy functions
|
||||
int flip1_open(PROGRAMMER *pgm, char *port_spec)
|
||||
{
|
||||
fprintf(stderr, "%s: Error: No USB support in this compile of avrdude\n",
|
||||
progname);
|
||||
return -1;
|
||||
}
|
||||
|
||||
int flip1_initialize(PROGRAMMER* pgm, AVRPART *part)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
void flip1_close(PROGRAMMER* pgm)
|
||||
{
|
||||
}
|
||||
|
||||
void flip1_enable(PROGRAMMER* pgm)
|
||||
{
|
||||
}
|
||||
|
||||
void flip1_disable(PROGRAMMER* pgm)
|
||||
{
|
||||
}
|
||||
|
||||
void flip1_display(PROGRAMMER* pgm, const char *prefix)
|
||||
{
|
||||
}
|
||||
|
||||
int flip1_program_enable(PROGRAMMER* pgm, AVRPART *part)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
int flip1_chip_erase(PROGRAMMER* pgm, AVRPART *part)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
int flip1_read_byte(PROGRAMMER* pgm, AVRPART *part, AVRMEM *mem,
|
||||
unsigned long addr, unsigned char *value)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
int flip1_write_byte(PROGRAMMER* pgm, AVRPART *part, AVRMEM *mem,
|
||||
unsigned long addr, unsigned char value)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
int flip1_paged_load(PROGRAMMER* pgm, AVRPART *part, AVRMEM *mem,
|
||||
unsigned int page_size, unsigned int addr, unsigned int n_bytes)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
int flip1_paged_write(PROGRAMMER* pgm, AVRPART *part, AVRMEM *mem,
|
||||
unsigned int page_size, unsigned int addr, unsigned int n_bytes)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
int flip1_read_sig_bytes(PROGRAMMER* pgm, AVRPART *part, AVRMEM *mem)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
void flip1_setup(PROGRAMMER * pgm)
|
||||
{
|
||||
}
|
||||
|
||||
void flip1_teardown(PROGRAMMER * pgm)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
#endif /* HAVE_LIBUSB */
|
||||
35
src/flip1.h
Normal file
35
src/flip1.h
Normal file
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* avrdude - A Downloader/Uploader for AVR device programmers
|
||||
* Copyright (C) 2014 Joerg Wunsch
|
||||
*
|
||||
* 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/* $Id$ */
|
||||
|
||||
#ifndef flip1_h
|
||||
#define flip1_h
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
extern const char flip1_desc[];
|
||||
extern void flip1_initpgm(PROGRAMMER * pgm);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* flip1_h */
|
||||
1002
src/flip2.c
Normal file
1002
src/flip2.c
Normal file
File diff suppressed because it is too large
Load Diff
35
src/flip2.h
Normal file
35
src/flip2.h
Normal file
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* avrdude - A Downloader/Uploader for AVR device programmers
|
||||
* Copyright (C) 2012 Kirill Levchenko
|
||||
*
|
||||
* 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/* $Id$ */
|
||||
|
||||
#ifndef flip2_h
|
||||
#define flip2_h
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
extern const char flip2_desc[];
|
||||
extern void flip2_initpgm(PROGRAMMER * pgm);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* flip2_h */
|
||||
39
src/freebsd_ppi.h
Normal file
39
src/freebsd_ppi.h
Normal file
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* avrdude - A Downloader/Uploader for AVR device programmers
|
||||
* Copyright (C) 2005 Joerg Wunsch
|
||||
*
|
||||
* 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/* $Id$ */
|
||||
|
||||
#ifndef freebsd_ppi_h
|
||||
#define freebsd_ppi_h
|
||||
|
||||
#include <dev/ppbus/ppi.h>
|
||||
|
||||
#define ppi_claim(fd) {}
|
||||
|
||||
#define ppi_release(fd) {}
|
||||
|
||||
#define DO_PPI_READ(fd, reg, valp) \
|
||||
(void)ioctl(fd, \
|
||||
(reg) == PPIDATA? PPIGDATA: ((reg) == PPICTRL? PPIGCTRL: PPIGSTATUS), \
|
||||
valp)
|
||||
#define DO_PPI_WRITE(fd, reg, valp) \
|
||||
(void)ioctl(fd, \
|
||||
(reg) == PPIDATA? PPISDATA: ((reg) == PPICTRL? PPISCTRL: PPISSTATUS), \
|
||||
valp)
|
||||
|
||||
#endif /* freebsd_ppi_h */
|
||||
1260
src/ft245r.c
Normal file
1260
src/ft245r.c
Normal file
File diff suppressed because it is too large
Load Diff
8
src/ft245r.h
Normal file
8
src/ft245r.h
Normal file
@@ -0,0 +1,8 @@
|
||||
#ifndef ft245r_h
|
||||
#define ft245r_h
|
||||
|
||||
extern const char ft245r_desc[];
|
||||
void ft245r_initpgm (PROGRAMMER * pgm);
|
||||
|
||||
|
||||
#endif /* ft245r_h */
|
||||
2567
src/jtag3.c
Normal file
2567
src/jtag3.c
Normal file
File diff suppressed because it is too large
Load Diff
62
src/jtag3.h
Normal file
62
src/jtag3.h
Normal file
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
* avrdude - A Downloader/Uploader for AVR device programmers
|
||||
* Copyright (C) 2012 Joerg Wunsch <j@uriah.heep.sax.de>
|
||||
*
|
||||
* 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/* $Id$ */
|
||||
|
||||
#ifndef jtag3_h
|
||||
#define jtag3_h
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
int jtag3_open_common(PROGRAMMER * pgm, char * port);
|
||||
int jtag3_send(PROGRAMMER * pgm, unsigned char * data, size_t len);
|
||||
int jtag3_recv(PROGRAMMER * pgm, unsigned char **msg);
|
||||
void jtag3_close(PROGRAMMER * pgm);
|
||||
int jtag3_getsync(PROGRAMMER * pgm, int mode);
|
||||
int jtag3_getparm(PROGRAMMER * pgm, unsigned char scope,
|
||||
unsigned char section, unsigned char parm,
|
||||
unsigned char *value, unsigned char length);
|
||||
int jtag3_setparm(PROGRAMMER * pgm, unsigned char scope,
|
||||
unsigned char section, unsigned char parm,
|
||||
unsigned char *value, unsigned char length);
|
||||
int jtag3_command(PROGRAMMER *pgm, unsigned char *cmd, unsigned int cmdlen,
|
||||
unsigned char **resp, const char *descr);
|
||||
extern const char jtag3_desc[];
|
||||
extern const char jtag3_dw_desc[];
|
||||
extern const char jtag3_pdi_desc[];
|
||||
extern const char jtag3_updi_desc[];
|
||||
void jtag3_initpgm (PROGRAMMER * pgm);
|
||||
void jtag3_dw_initpgm (PROGRAMMER * pgm);
|
||||
void jtag3_pdi_initpgm (PROGRAMMER * pgm);
|
||||
void jtag3_updi_initpgm (PROGRAMMER * pgm);
|
||||
|
||||
/*
|
||||
* These functions are referenced from stk500v2.c for JTAGICE3 in
|
||||
* one of the STK500v2 modi.
|
||||
*/
|
||||
void jtag3_setup(PROGRAMMER * pgm);
|
||||
void jtag3_teardown(PROGRAMMER * pgm);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
393
src/jtag3_private.h
Normal file
393
src/jtag3_private.h
Normal file
@@ -0,0 +1,393 @@
|
||||
/*
|
||||
* avrdude - A Downloader/Uploader for AVR device programmers
|
||||
* Copyright (C) 2012 Joerg Wunsch <j@uriah.heep.sax.de>
|
||||
*
|
||||
*
|
||||
* 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/* $Id$ */
|
||||
|
||||
|
||||
/*
|
||||
* JTAGICE3 definitions
|
||||
* Reverse-engineered from various USB traces.
|
||||
*/
|
||||
|
||||
#if !defined(JTAG3_PRIVATE_EXPORTED)
|
||||
/*
|
||||
* Communication with the JTAGICE3 uses three data endpoints:
|
||||
*
|
||||
* Endpoint 0x01 (OUT) and 0x82 (IN) are the usual conversation
|
||||
* endpoints, with a maximal packet size of 512 octets. The
|
||||
* JTAGICE3 does *not* work on older USB 1.1 hubs that would only
|
||||
* allow for 64-octet max packet size.
|
||||
*
|
||||
* Endpoint 0x83 (IN) is also a bulk endpoint, with a max packetsize
|
||||
* of 64 octets. This endpoint is used by the ICE to deliver events
|
||||
* from the ICE.
|
||||
*
|
||||
* The request (host -> ICE, EP 0x01) format is:
|
||||
*
|
||||
* +---------------------------------------------
|
||||
* | 0 | 1 | 2 . 3 | 4 | 5 | 6 | ...
|
||||
* | | | | | | |
|
||||
* | token |dummy|serial# |scope| cmd |dummy| optional data
|
||||
* | 0x0e | 0 | NNNN | SS | CC | 0 | ...
|
||||
* +---------------------------------------------
|
||||
*
|
||||
* Both dummy bytes are always 0. The "scope" identifier appears
|
||||
* to distinguish commands (responses, events, parameters) roughly:
|
||||
*
|
||||
* 0x01 - general scope ("hello", "goodbye", firmware info, target
|
||||
* voltage readout)
|
||||
* 0x11 - scope for AVR in ISP mode (basically a wrapper around
|
||||
* the AVRISPmkII commands, as usual)
|
||||
* 0x12 - scope for AVR (JTAG, PDI, debugWIRE)
|
||||
*
|
||||
* The serial number is counted up.
|
||||
*
|
||||
*
|
||||
* The response (ICE -> host, EP 0x82) format is:
|
||||
*
|
||||
* +--------------------------------------------------+
|
||||
* | 0 | 1 . 2 | 3 | 4 | ... | N |
|
||||
* | | | | | | |
|
||||
* | token |serial# |scope| rsp | optional data |dummy|
|
||||
* | 0x0e | NNNN | SS | RR | ... | 0 |
|
||||
* +--------------------------------------------------+
|
||||
*
|
||||
* The response's serial number is mirrored from the request, but the
|
||||
* dummy byte before the serial number is left out. However, another
|
||||
* zero dummy byte is always attached to the end of the response data.
|
||||
* Response codes are similar to the JTAGICEmkII, 0x80 is a generic
|
||||
* "OK" response, other responses above 0x80 indicate various data
|
||||
* responses (parameter read, memory read, PC value), and 0xa0 is a
|
||||
* generic "failure" response. It appears the failure response gets
|
||||
* another byte appended (probably indicating the reason) after the
|
||||
* 0 dummy byte, but there's not enough analysis material so far.
|
||||
*
|
||||
*
|
||||
* The event format (EP 0x83) is:
|
||||
*
|
||||
* +----------------------------------------
|
||||
* | 0 | 1 | 2 . 3 | 4 | 5 | ...
|
||||
* | | | | | |
|
||||
* | token |dummy|serial# |scope| evt | data
|
||||
* | 0x0e | 0 | NNNN | SS | EV | ...
|
||||
* +----------------------------------------
|
||||
*/
|
||||
#define TOKEN 0x0e
|
||||
|
||||
#endif /* JTAG3_PRIVATE_EXPORTED */
|
||||
|
||||
#define SCOPE_INFO 0x00
|
||||
#define SCOPE_GENERAL 0x01
|
||||
#define SCOPE_AVR_ISP 0x11
|
||||
#define SCOPE_AVR 0x12
|
||||
|
||||
/* Info scope */
|
||||
#define CMD3_GET_INFO 0x00
|
||||
|
||||
/* byte after GET_INFO is always 0, next is: */
|
||||
# define CMD3_INFO_NAME 0x80 /* JTAGICE3 */
|
||||
# define CMD3_INFO_SERIAL 0x81 /* J3xxxxxxxxxx */
|
||||
|
||||
/* Generic scope */
|
||||
#define CMD3_SET_PARAMETER 0x01
|
||||
#define CMD3_GET_PARAMETER 0x02
|
||||
#define CMD3_SIGN_ON 0x10
|
||||
#define CMD3_SIGN_OFF 0x11 /* takes one parameter? */
|
||||
#define CMD3_GET_ID 0x12
|
||||
#define CMD3_START_DW_DEBUG 0x13
|
||||
#define CMD3_MONCON_DISABLE 0x17
|
||||
|
||||
/* AVR ISP scope: no commands of its own */
|
||||
|
||||
/* AVR scope */
|
||||
//#define CMD3_SET_PARAMETER 0x01
|
||||
//#define CMD3_GET_PARAMETER 0x02
|
||||
//#define CMD3_SIGN_ON 0x10 /* an additional signon/-off pair */
|
||||
//#define CMD3_SIGN_OFF 0x11
|
||||
#define CMD3_ENTER_PROGMODE 0x15
|
||||
#define CMD3_LEAVE_PROGMODE 0x16
|
||||
#define CMD3_ERASE_MEMORY 0x20
|
||||
#define CMD3_READ_MEMORY 0x21
|
||||
#define CMD3_WRITE_MEMORY 0x23
|
||||
#define CMD3_READ_PC 0x35
|
||||
|
||||
/* ICE responses */
|
||||
#define RSP3_OK 0x80
|
||||
#define RSP3_INFO 0x81
|
||||
#define RSP3_PC 0x83
|
||||
#define RSP3_DATA 0x84
|
||||
#define RSP3_FAILED 0xA0
|
||||
|
||||
#define RSP3_STATUS_MASK 0xE0
|
||||
|
||||
/* possible failure codes that could be appended to RSP3_FAILED: */
|
||||
# define RSP3_FAIL_DEBUGWIRE 0x10
|
||||
# define RSP3_FAIL_PDI 0x1B
|
||||
# define RSP3_FAIL_NO_ANSWER 0x20
|
||||
# define RSP3_FAIL_NO_TARGET_POWER 0x22
|
||||
# define RSP3_FAIL_WRONG_MODE 0x32 /* progmode vs. non-prog */
|
||||
# define RSP3_FAIL_UNSUPP_MEMORY 0x34 /* unsupported memory type */
|
||||
# define RSP3_FAIL_WRONG_LENGTH 0x35 /* wrong lenth for mem access */
|
||||
# define RSP3_FAIL_OCD_LOCKED 0x44 /* device is locked */
|
||||
# define RSP3_FAIL_NOT_UNDERSTOOD 0x91
|
||||
|
||||
/* ICE events */
|
||||
#define EVT3_BREAK 0x40 /* AVR scope */
|
||||
#define EVT3_SLEEP 0x11 /* General scope, also wakeup */
|
||||
#define EVT3_POWER 0x10 /* General scope */
|
||||
|
||||
/* memory types */
|
||||
#define MTYPE_SRAM 0x20 /* target's SRAM or [ext.] IO registers */
|
||||
#define MTYPE_EEPROM 0x22 /* EEPROM, what way? */
|
||||
#define MTYPE_SPM 0xA0 /* flash through LPM/SPM */
|
||||
#define MTYPE_FLASH_PAGE 0xB0 /* flash in programming mode */
|
||||
#define MTYPE_EEPROM_PAGE 0xB1 /* EEPROM in programming mode */
|
||||
#define MTYPE_FUSE_BITS 0xB2 /* fuse bits in programming mode */
|
||||
#define MTYPE_LOCK_BITS 0xB3 /* lock bits in programming mode */
|
||||
#define MTYPE_SIGN_JTAG 0xB4 /* signature in programming mode */
|
||||
#define MTYPE_OSCCAL_BYTE 0xB5 /* osccal cells in programming mode */
|
||||
#define MTYPE_FLASH 0xc0 /* xmega (app.) flash - undocumented in AVR067 */
|
||||
#define MTYPE_BOOT_FLASH 0xc1 /* xmega boot flash - undocumented in AVR067 */
|
||||
#define MTYPE_EEPROM_XMEGA 0xc4 /* xmega EEPROM in debug mode - undocumented in AVR067 */
|
||||
#define MTYPE_USERSIG 0xc5 /* xmega user signature - undocumented in AVR067 */
|
||||
#define MTYPE_PRODSIG 0xc6 /* xmega production signature - undocumented in AVR067 */
|
||||
#define MTYPE_SIB 0xD3 /* AVR8X System Information Block */
|
||||
|
||||
/*
|
||||
* SET and GET context definitions
|
||||
*/
|
||||
#define SET_GET_CTXT_CONFIG 0x00 /* Configuration */
|
||||
#define SET_GET_CTXT_PHYSICAL 0x01 /* Physical interface related */
|
||||
#define SET_GET_CTXT_DEVICE 0x02 /* Device specific settings */
|
||||
#define SET_GET_CTXT_OPTIONS 0x03 /* Option-related settings */
|
||||
#define SET_GET_CTXT_SESSION 0x04 /* Session-related settings */
|
||||
|
||||
/*
|
||||
* Parameters are divided into sections, where the section number
|
||||
* precedes each parameter address. There are distinct parameter
|
||||
* sets for generic and AVR scope.
|
||||
*/
|
||||
#define PARM3_HW_VER 0x00 /* section 0, generic scope, 1 byte */
|
||||
#define PARM3_FW_MAJOR 0x01 /* section 0, generic scope, 1 byte */
|
||||
#define PARM3_FW_MINOR 0x02 /* section 0, generic scope, 1 byte */
|
||||
#define PARM3_FW_RELEASE 0x03 /* section 0, generic scope, 1 byte;
|
||||
* always asked for by Atmel Studio,
|
||||
* but never displayed there */
|
||||
#define PARM3_VTARGET 0x00 /* section 1, generic scope, 2 bytes,
|
||||
* in millivolts */
|
||||
#define PARM3_DEVICEDESC 0x00 /* section 2, memory etc. configuration,
|
||||
* 31 bytes for tiny/mega AVR, 47 bytes
|
||||
* for Xmega; is also used in command
|
||||
* 0x36 in JTAGICEmkII, starting with
|
||||
* firmware 7.x */
|
||||
|
||||
#define PARM3_ARCH 0x00 /* section 0, AVR scope, 1 byte */
|
||||
# define PARM3_ARCH_TINY 1 /* also small megaAVR with ISP/DW only */
|
||||
# define PARM3_ARCH_MEGA 2
|
||||
# define PARM3_ARCH_XMEGA 3
|
||||
# define PARM3_ARCH_UPDI 5 /* AVR devices with UPDI i/f */
|
||||
|
||||
#define PARM3_SESS_PURPOSE 0x01 /* section 0, AVR scope, 1 byte */
|
||||
# define PARM3_SESS_PROGRAMMING 1
|
||||
# define PARM3_SESS_DEBUGGING 2
|
||||
|
||||
#define PARM3_CONNECTION 0x00 /* section 1, AVR scope, 1 byte */
|
||||
# define PARM3_CONN_ISP 1
|
||||
# define PARM3_CONN_JTAG 4
|
||||
# define PARM3_CONN_DW 5
|
||||
# define PARM3_CONN_PDI 6
|
||||
# define PARM3_CONN_UPDI 8
|
||||
|
||||
|
||||
#define PARM3_JTAGCHAIN 0x01 /* JTAG chain info, AVR scope (units
|
||||
* before/after, bits before/after), 4
|
||||
* bytes */
|
||||
|
||||
/*
|
||||
* Physical context parameters
|
||||
*/
|
||||
#define PARM3_CLK_MEGA_PROG 0x20 /* section 1, AVR scope, 2 bytes (kHz) */
|
||||
#define PARM3_CLK_MEGA_DEBUG 0x21 /* section 1, AVR scope, 2 bytes (kHz) */
|
||||
#define PARM3_CLK_XMEGA_JTAG 0x30 /* section 1, AVR scope, 2 bytes (kHz) */
|
||||
#define PARM3_CLK_XMEGA_PDI 0x31 /* section 1, AVR scope, 2 bytes (kHz) */
|
||||
|
||||
/*
|
||||
* Options context parameters
|
||||
*/
|
||||
#define PARM3_OPT_12V_UPDI_ENABLE 0x06
|
||||
#define PARM3_OPT_CHIP_ERASE_TO_ENTER 0x07
|
||||
|
||||
/* Xmega erase memory types, for CMND_XMEGA_ERASE */
|
||||
#define XMEGA_ERASE_CHIP 0x00
|
||||
#define XMEGA_ERASE_APP 0x01
|
||||
#define XMEGA_ERASE_BOOT 0x02
|
||||
#define XMEGA_ERASE_EEPROM 0x03
|
||||
#define XMEGA_ERASE_APP_PAGE 0x04
|
||||
#define XMEGA_ERASE_BOOT_PAGE 0x05
|
||||
#define XMEGA_ERASE_EEPROM_PAGE 0x06
|
||||
#define XMEGA_ERASE_USERSIG 0x07
|
||||
|
||||
/* EDBG vendor commands */
|
||||
#define EDBG_VENDOR_AVR_CMD 0x80
|
||||
#define EDBG_VENDOR_AVR_RSP 0x81
|
||||
#define EDBG_VENDOR_AVR_EVT 0x82
|
||||
|
||||
/* CMSIS-DAP commands */
|
||||
#define CMSISDAP_CMD_INFO 0x00 /* get info, followed by INFO byte */
|
||||
# define CMSISDAP_INFO_VID 0x01 /* vendor ID (string) */
|
||||
# define CMSISDAP_INFO_PID 0x02 /* product ID (string) */
|
||||
# define CMSISDAP_INFO_SERIAL 0x03 /* serial number (string) */
|
||||
# define CMSISDAP_INFO_FIRMWARE 0x04 /* firmware version (string) */
|
||||
# define CMSISDAP_INFO_TARGET_VENDOR 0x05 /* target device vendor (string) */
|
||||
# define CMSISDAP_INFO_TARGET_NAME 0x06 /* target device name (string) */
|
||||
# define CMSISDAP_INFO_CAPABILITIES 0xF0 /* debug unit capabilities (byte) */
|
||||
# define CMSISDAP_INFO_PACKET_COUNT 0xFE /* packet count (byte) (which packets, anyway?) */
|
||||
# define CMSISDAP_INFO_PACKET_SIZE 0xFF /* packet size (short) */
|
||||
|
||||
#define CMSISDAP_CMD_LED 0x01 /* LED control, followed by LED number and on/off byte */
|
||||
# define CMSISDAP_LED_CONNECT 0x00 /* connect LED */
|
||||
# define CMSISDAP_LED_RUNNING 0x01 /* running LED */
|
||||
|
||||
#define CMSISDAP_CMD_CONNECT 0x02 /* connect to target, followed by DAP mode */
|
||||
# define CMSISDAP_CONN_DEFAULT 0x00
|
||||
# define CMSISDAP_CONN_SWD 0x01 /* serial wire debug */
|
||||
# define CMSISDAP_CONN_JTAG 0x02 /* JTAG mode */
|
||||
|
||||
#define CMSISDAP_CMD_DISCONNECT 0x03 /* disconnect from target */
|
||||
|
||||
#define CMSISDAP_XFR_CONFIGURE 0x04 /* configure transfers; idle cycles (byte);
|
||||
wait retry (short); match retry (short) */
|
||||
|
||||
#define CMSISDAP_CMD_WRITEAPBORT 0x08 /* write to CoreSight ABORT register of target */
|
||||
|
||||
#define CMSISDAP_CMD_DELAY 0x09 /* delay for number of microseconds (short) */
|
||||
|
||||
#define CMSISDAP_CMD_RESET 0x0A /* reset target */
|
||||
|
||||
#define CMSISDAP_CMD_SWJ_CLOCK 0x11 /* SWD/JTAG clock, (word) */
|
||||
|
||||
#define CMSISDAP_CMD_SWD_CONFIGURE 0x13 /* configure SWD protocol; (byte) */
|
||||
|
||||
#define DEFAULT_MINIMUM_CHARACTERISED_DIV1_VOLTAGE_MV 4500 // Default minimum voltage for 32M => 4.5V
|
||||
#define DEFAULT_MINIMUM_CHARACTERISED_DIV2_VOLTAGE_MV 2700 // Default minimum voltage for 16M => 2.7V
|
||||
#define DEFAULT_MINIMUM_CHARACTERISED_DIV4_VOLTAGE_MV 2200 // Default minimum voltage for 8M => 2.2V
|
||||
#define DEFAULT_MINIMUM_CHARACTERISED_DIV8_VOLTAGE_MV 1500 // Default minimum voltage for 4M => 1.5V
|
||||
#define MAX_FREQUENCY_DEDICATED_UPDI_PIN 1500
|
||||
#define MAX_FREQUENCY_SHARED_UPDI_PIN 750
|
||||
#define UPDI_ADDRESS_MODE_16BIT 0
|
||||
#define UPDI_ADDRESS_MODE_24BIT 1
|
||||
#define FUSES_SYSCFG0_OFFSET 5
|
||||
|
||||
#if !defined(JTAG3_PRIVATE_EXPORTED)
|
||||
|
||||
struct mega_device_desc {
|
||||
unsigned char flash_page_size[2]; // in bytes
|
||||
unsigned char flash_size[4]; // in bytes
|
||||
unsigned char dummy1[4]; // always 0
|
||||
unsigned char boot_address[4]; // maximal (BOOTSZ = 3) bootloader
|
||||
// address, in 16-bit words (!)
|
||||
unsigned char sram_offset[2]; // pointing behind IO registers
|
||||
unsigned char eeprom_size[2];
|
||||
unsigned char eeprom_page_size;
|
||||
unsigned char ocd_revision; // see XML; basically:
|
||||
// t13*, t2313*, t4313: 0
|
||||
// all other DW devices: 1
|
||||
// ATmega128(A): 1 (!)
|
||||
// ATmega16*,162,169*,32*,64*: 2
|
||||
// ATmega2560/2561: 4
|
||||
// all other megaAVR devices: 3
|
||||
unsigned char always_one; // always = 1
|
||||
unsigned char allow_full_page_bitstream; // old AVRs, see XML
|
||||
unsigned char dummy2[2]; // always 0
|
||||
// all IO addresses below are given
|
||||
// in IO number space (without
|
||||
// offset 0x20), even though e.g.
|
||||
// OSCCAL always resides outside
|
||||
unsigned char idr_address; // IDR, aka. OCDR
|
||||
unsigned char eearh_address; // EEPROM access
|
||||
unsigned char eearl_address;
|
||||
unsigned char eecr_address;
|
||||
unsigned char eedr_address;
|
||||
unsigned char spmcr_address;
|
||||
unsigned char osccal_address;
|
||||
};
|
||||
|
||||
|
||||
/* Xmega device descriptor */
|
||||
struct xmega_device_desc {
|
||||
unsigned char nvm_app_offset[4]; // NVM offset for application flash
|
||||
unsigned char nvm_boot_offset[4]; // NVM offset for boot flash
|
||||
unsigned char nvm_eeprom_offset[4]; // NVM offset for EEPROM
|
||||
unsigned char nvm_fuse_offset[4]; // NVM offset for fuses
|
||||
unsigned char nvm_lock_offset[4]; // NVM offset for lock bits
|
||||
unsigned char nvm_user_sig_offset[4]; // NVM offset for user signature row
|
||||
unsigned char nvm_prod_sig_offset[4]; // NVM offset for production sign. row
|
||||
unsigned char nvm_data_offset[4]; // NVM offset for data memory (SRAM + IO)
|
||||
unsigned char app_size[4]; // size of application flash
|
||||
unsigned char boot_size[2]; // size of boot flash
|
||||
unsigned char flash_page_size[2]; // flash page size
|
||||
unsigned char eeprom_size[2]; // size of EEPROM
|
||||
unsigned char eeprom_page_size; // EEPROM page size
|
||||
unsigned char nvm_base_addr[2]; // IO space base address of NVM controller
|
||||
unsigned char mcu_base_addr[2]; // IO space base address of MCU control
|
||||
};
|
||||
|
||||
/* UPDI device descriptor */
|
||||
struct updi_device_desc {
|
||||
unsigned char prog_base[2];
|
||||
unsigned char flash_page_size;
|
||||
unsigned char eeprom_page_size;
|
||||
unsigned char nvm_base_addr[2];
|
||||
unsigned char ocd_base_addr[2];
|
||||
|
||||
// Configuration below, except for "Extended memory support", is only used by kits with
|
||||
// embedded debuggers (XPlained, Curiosity, ...).
|
||||
unsigned char default_min_div1_voltage[2]; // Default minimum voltage for 32M => 4.5V -> 4500
|
||||
unsigned char default_min_div2_voltage[2]; // Default minimum voltage for 16M => 2.7V -> 2700
|
||||
unsigned char default_min_div4_voltage[2]; // Default minimum voltage for 8M => 2.2V -> 2200
|
||||
unsigned char default_min_div8_voltage[2]; // Default minimum voltage for 4M => 1.5V -> 1500
|
||||
|
||||
unsigned char pdi_pad_fmax[2]; // 750
|
||||
|
||||
unsigned char flash_bytes[4]; // Flash size in bytes
|
||||
unsigned char eeprom_bytes[2]; // EEPROM size in bytes
|
||||
unsigned char user_sig_bytes[2]; // UserSignture size in bytes
|
||||
unsigned char fuses_bytes; // Fuses size in bytes
|
||||
|
||||
unsigned char syscfg_offset; // Offset of SYSCFG0 within FUSE space
|
||||
unsigned char syscfg_write_mask_and; // AND mask to apply to SYSCFG0 when writing
|
||||
unsigned char syscfg_write_mask_or; // OR mask to apply to SYSCFG0 when writing
|
||||
unsigned char syscfg_erase_mask_and; // AND mask to apply to SYSCFG0 after erase
|
||||
unsigned char syscfg_erase_mask_or; // OR mask to apply to SYSCFG0 after erase
|
||||
|
||||
unsigned char eeprom_base[2]; // Base address for EEPROM memory
|
||||
unsigned char user_sig_base[2]; // Base address for UserSignature memory
|
||||
unsigned char signature_base[2]; // Base address for Signature memory
|
||||
unsigned char fuses_base[2]; // Base address for Fuses memory
|
||||
unsigned char lockbits_base[2]; // Base address for Lockbits memory
|
||||
|
||||
unsigned char device_id[2]; // Two last bytes of the device ID
|
||||
|
||||
// Extended memory support. Needed for flash >= 64kb
|
||||
unsigned char prog_base_msb; // Extends prog_base, used in 24-bit mode
|
||||
unsigned char flash_page_size_msb; // Extends flash_page_size, used in 24-bit mode
|
||||
|
||||
unsigned char address_mode; // 0x00 = 16-bit mode, 0x01 = 24-bit mode
|
||||
};
|
||||
#endif /* JTAG3_PRIVATE_EXPORTED */
|
||||
1366
src/jtagmkI.c
Normal file
1366
src/jtagmkI.c
Normal file
File diff suppressed because it is too large
Load Diff
36
src/jtagmkI.h
Normal file
36
src/jtagmkI.h
Normal file
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* avrdude - A Downloader/Uploader for AVR device programmers
|
||||
* Copyright (C) 2002-2004 Brian S. Dean <bsd@bsdhome.com>
|
||||
*
|
||||
* 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/* $Id$ */
|
||||
|
||||
#ifndef jtagmkI_h
|
||||
#define jtagmkI_h
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
extern const char jtagmkI_desc[];
|
||||
void jtagmkI_initpgm (PROGRAMMER * pgm);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
4027
src/jtagmkII.c
Normal file
4027
src/jtagmkII.c
Normal file
File diff suppressed because it is too large
Load Diff
63
src/jtagmkII.h
Normal file
63
src/jtagmkII.h
Normal file
@@ -0,0 +1,63 @@
|
||||
/*
|
||||
* avrdude - A Downloader/Uploader for AVR device programmers
|
||||
* Copyright (C) 2002-2004, 2006 Brian S. Dean <bsd@bsdhome.com>
|
||||
*
|
||||
* 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/* $Id$ */
|
||||
|
||||
#ifndef jtagmkII_h
|
||||
#define jtagmkII_h
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
int jtagmkII_send(PROGRAMMER * pgm, unsigned char * data, size_t len);
|
||||
int jtagmkII_recv(PROGRAMMER * pgm, unsigned char **msg);
|
||||
void jtagmkII_close(PROGRAMMER * pgm);
|
||||
int jtagmkII_getsync(PROGRAMMER * pgm, int mode);
|
||||
int jtagmkII_getparm(PROGRAMMER * pgm, unsigned char parm,
|
||||
unsigned char * value);
|
||||
|
||||
extern const char jtagmkII_desc[];
|
||||
extern const char jtagmkII_avr32_desc[];
|
||||
extern const char jtagmkII_dw_desc[];
|
||||
extern const char jtagmkII_pdi_desc[];
|
||||
extern const char jtagmkII_dragon_desc[];
|
||||
extern const char jtagmkII_dragon_dw_desc[];
|
||||
extern const char jtagmkII_dragon_pdi_desc[];
|
||||
void jtagmkII_initpgm (PROGRAMMER * pgm);
|
||||
void jtagmkII_avr32_initpgm (PROGRAMMER * pgm);
|
||||
void jtagmkII_dw_initpgm (PROGRAMMER * pgm);
|
||||
void jtagmkII_pdi_initpgm (PROGRAMMER * pgm);
|
||||
void jtagmkII_dragon_initpgm (PROGRAMMER * pgm);
|
||||
void jtagmkII_dragon_dw_initpgm (PROGRAMMER * pgm);
|
||||
void jtagmkII_dragon_pdi_initpgm (PROGRAMMER * pgm);
|
||||
|
||||
/*
|
||||
* These functions are referenced from stk500v2.c for JTAG ICE mkII
|
||||
* and AVR Dragon programmers running in one of the STK500v2
|
||||
* modi.
|
||||
*/
|
||||
void jtagmkII_setup(PROGRAMMER * pgm);
|
||||
void jtagmkII_teardown(PROGRAMMER * pgm);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
385
src/jtagmkII_private.h
Normal file
385
src/jtagmkII_private.h
Normal file
@@ -0,0 +1,385 @@
|
||||
/*
|
||||
* avrdude - A Downloader/Uploader for AVR device programmers
|
||||
* Copyright (C) 2005, 2006 Joerg Wunsch <j@uriah.heep.sax.de>
|
||||
*
|
||||
*
|
||||
* 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/* $Id$ */
|
||||
|
||||
|
||||
/*
|
||||
* JTAG ICE mkII definitions
|
||||
* Taken from Appnote AVR067
|
||||
*/
|
||||
|
||||
#if !defined(JTAGMKII_PRIVATE_EXPORTED)
|
||||
/*
|
||||
* Communication with the JTAG ICE works in frames. The protocol
|
||||
* somewhat resembles the STK500v2 protocol, yet it is sufficiently
|
||||
* different to prevent a direct code reuse. :-(
|
||||
*
|
||||
* Frame format:
|
||||
*
|
||||
* +---------------------------------------------------------------+
|
||||
* | 0 | 1 . 2 | 3 . 4 . 5 . 6 | 7 | ... | N-1 . N |
|
||||
* | | | | | | |
|
||||
* | start | LSB MSB | LSB ....... MSB | token | msg | LSB MSB |
|
||||
* | 0x1B | sequence# | message size | 0x0E | | CRC16 |
|
||||
* +---------------------------------------------------------------+
|
||||
*
|
||||
* Each request message will be returned by a response with a matching
|
||||
* sequence #. Sequence # 0xffff is reserved for asynchronous event
|
||||
* notifications that will be sent by the ICE without a request
|
||||
* message (e.g. when the target hit a breakpoint).
|
||||
*
|
||||
* The message size excludes the framing overhead (10 bytes).
|
||||
*
|
||||
* The first byte of the message is always the request or response
|
||||
* code, which is roughly classified as:
|
||||
*
|
||||
* . Messages (commands) use 0x00 through 0x3f. (The documentation
|
||||
* claims that messages start at 0x01, but actually CMND_SIGN_OFF is
|
||||
* 0x00.)
|
||||
* . Internal commands use 0x40 through 0x7f (not documented).
|
||||
* . Success responses use 0x80 through 0x9f.
|
||||
* . Failure responses use 0xa0 through 0xbf.
|
||||
* . Events use 0xe0 through 0xff.
|
||||
*/
|
||||
#define MESSAGE_START 0x1b
|
||||
#define TOKEN 0x0e
|
||||
|
||||
/*
|
||||
* Max message size we are willing to accept. Prevents us from trying
|
||||
* to allocate too much VM in case we received a nonsensical packet
|
||||
* length. We have to allocate the buffer as soon as we've got the
|
||||
* length information (and thus have to trust that information by that
|
||||
* time at first), as the final CRC check can only be done once the
|
||||
* entire packet came it.
|
||||
*/
|
||||
#define MAX_MESSAGE 100000
|
||||
|
||||
#endif /* JTAGMKII_PRIVATE_EXPORTED */
|
||||
|
||||
/* ICE command codes */
|
||||
#define CMND_SIGN_OFF 0x00
|
||||
#define CMND_GET_SIGN_ON 0x01
|
||||
#define CMND_SET_PARAMETER 0x02
|
||||
#define CMND_GET_PARAMETER 0x03
|
||||
#define CMND_WRITE_MEMORY 0x04
|
||||
#define CMND_READ_MEMORY 0x05
|
||||
#define CMND_WRITE_PC 0x06
|
||||
#define CMND_READ_PC 0x07
|
||||
#define CMND_GO 0x08
|
||||
#define CMND_SINGLE_STEP 0x09
|
||||
#define CMND_FORCED_STOP 0x0A
|
||||
#define CMND_RESET 0x0B
|
||||
#define CMND_SET_DEVICE_DESCRIPTOR 0x0C
|
||||
#define CMND_ERASEPAGE_SPM 0x0D
|
||||
#define CMND_GET_SYNC 0x0f
|
||||
#define CMND_SELFTEST 0x10
|
||||
#define CMND_SET_BREAK 0x11
|
||||
#define CMND_GET_BREAK 0x12
|
||||
#define CMND_CHIP_ERASE 0x13
|
||||
#define CMND_ENTER_PROGMODE 0x14
|
||||
#define CMND_LEAVE_PROGMODE 0x15
|
||||
#define CMND_SET_N_PARAMETERS 0x16
|
||||
#define CMND_CLR_BREAK 0x1A
|
||||
#define CMND_RUN_TO_ADDR 0x1C
|
||||
#define CMND_SPI_CMD 0x1D
|
||||
#define CMND_CLEAR_EVENTS 0x22
|
||||
#define CMND_RESTORE_TARGET 0x23
|
||||
#define CMND_GET_IR 0x24
|
||||
#define CMND_GET_xxx 0x25
|
||||
#define CMND_WRITE_SAB 0x28
|
||||
#define CMND_READ_SAB 0x29
|
||||
#define CMND_RESET_AVR 0x2B
|
||||
#define CMND_READ_MEMORY32 0x2C
|
||||
#define CMND_WRITE_MEMORY32 0x2D
|
||||
#define CMND_ISP_PACKET 0x2F
|
||||
#define CMND_XMEGA_ERASE 0x34
|
||||
#define CMND_SET_XMEGA_PARAMS 0x36 // undocumented in AVR067
|
||||
|
||||
|
||||
/* ICE responses */
|
||||
#define RSP_OK 0x80
|
||||
#define RSP_PARAMETER 0x81
|
||||
#define RSP_MEMORY 0x82
|
||||
#define RSP_GET_BREAK 0x83
|
||||
#define RSP_PC 0x84
|
||||
#define RSP_SELFTEST 0x85
|
||||
#define RSP_SIGN_ON 0x86
|
||||
#define RSP_SPI_DATA 0x88
|
||||
#define RSP_FAILED 0xA0
|
||||
#define RSP_ILLEGAL_PARAMETER 0xA1
|
||||
#define RSP_ILLEGAL_MEMORY_TYPE 0xA2
|
||||
#define RSP_ILLEGAL_MEMORY_RANGE 0xA3
|
||||
#define RSP_ILLEGAL_EMULATOR_MODE 0xA4
|
||||
#define RSP_ILLEGAL_MCU_STATE 0xA5
|
||||
#define RSP_ILLEGAL_VALUE 0xA6
|
||||
#define RSP_SET_N_PARAMETERS 0xA7
|
||||
#define RSP_ILLEGAL_BREAKPOINT 0xA8
|
||||
#define RSP_ILLEGAL_JTAG_ID 0xA9
|
||||
#define RSP_ILLEGAL_COMMAND 0xAA
|
||||
#define RSP_NO_TARGET_POWER 0xAB
|
||||
#define RSP_DEBUGWIRE_SYNC_FAILED 0xAC
|
||||
#define RSP_ILLEGAL_POWER_STATE 0xAD
|
||||
|
||||
/* ICE events */
|
||||
#define EVT_BREAK 0xE0
|
||||
#define EVT_RUN 0xE1
|
||||
#define EVT_ERROR_PHY_FORCE_BREAK_TIMEOUT 0xE2
|
||||
#define EVT_ERROR_PHY_RELEASE_BREAK_TIMEOUT 0xE3
|
||||
#define EVT_TARGET_POWER_ON 0xE4
|
||||
#define EVT_TARGET_POWER_OFF 0xE5
|
||||
#define EVT_DEBUG 0xE6
|
||||
#define EVT_EXT_RESET 0xE7
|
||||
#define EVT_TARGET_SLEEP 0xE8
|
||||
#define EVT_TARGET_WAKEUP 0xE9
|
||||
#define EVT_ICE_POWER_ERROR_STATE 0xEA
|
||||
#define EVT_ICE_POWER_OK 0xEB
|
||||
#define EVT_IDR_DIRTY 0xEC
|
||||
#define EVT_ERROR_PHY_MAX_BIT_LENGTH_DIFF 0xED
|
||||
#define EVT_NONE 0xEF
|
||||
#define EVT_ERROR_PHY_SYNC_TIMEOUT 0xF0
|
||||
#define EVT_PROGRAM_BREAK 0xF1
|
||||
#define EVT_PDSB_BREAK 0xF2
|
||||
#define EVT_PDSMB_BREAK 0xF3
|
||||
#define EVT_ERROR_PHY_SYNC_TIMEOUT_BAUD 0xF4
|
||||
#define EVT_ERROR_PHY_SYNC_OUT_OF_RANGE 0xF5
|
||||
#define EVT_ERROR_PHY_SYNC_WAIT_TIMEOUT 0xF6
|
||||
#define EVT_ERROR_PHY_RECEIVE_TIMEOUT 0xF7
|
||||
#define EVT_ERROR_PHY_RECEIVED_BREAK 0xF8
|
||||
#define EVT_ERROR_PHY_OPT_RECEIVE_TIMEOUT 0xF9
|
||||
#define EVT_ERROR_PHY_OPT_RECEIVED_BREAK 0xFA
|
||||
#define EVT_RESULT_PHY_NO_ACTIVITY 0xFB
|
||||
|
||||
/* memory types for CMND_{READ,WRITE}_MEMORY */
|
||||
#define MTYPE_IO_SHADOW 0x30 /* cached IO registers? */
|
||||
#define MTYPE_SRAM 0x20 /* target's SRAM or [ext.] IO registers */
|
||||
#define MTYPE_EEPROM 0x22 /* EEPROM, what way? */
|
||||
#define MTYPE_EVENT 0x60 /* ICE event memory */
|
||||
#define MTYPE_SPM 0xA0 /* flash through LPM/SPM */
|
||||
#define MTYPE_FLASH_PAGE 0xB0 /* flash in programming mode */
|
||||
#define MTYPE_EEPROM_PAGE 0xB1 /* EEPROM in programming mode */
|
||||
#define MTYPE_FUSE_BITS 0xB2 /* fuse bits in programming mode */
|
||||
#define MTYPE_LOCK_BITS 0xB3 /* lock bits in programming mode */
|
||||
#define MTYPE_SIGN_JTAG 0xB4 /* signature in programming mode */
|
||||
#define MTYPE_OSCCAL_BYTE 0xB5 /* osccal cells in programming mode */
|
||||
#define MTYPE_CAN 0xB6 /* CAN mailbox */
|
||||
#define MTYPE_FLASH 0xc0 /* xmega (app.) flash - undocumented in AVR067 */
|
||||
#define MTYPE_BOOT_FLASH 0xc1 /* xmega boot flash - undocumented in AVR067 */
|
||||
#define MTYPE_EEPROM_XMEGA 0xc4 /* xmega EEPROM in debug mode - undocumented in AVR067 */
|
||||
#define MTYPE_USERSIG 0xc5 /* xmega user signature - undocumented in AVR067 */
|
||||
#define MTYPE_PRODSIG 0xc6 /* xmega production signature - undocumented in AVR067 */
|
||||
|
||||
/* (some) ICE parameters, for CMND_{GET,SET}_PARAMETER */
|
||||
#define PAR_HW_VERSION 0x01
|
||||
#define PAR_FW_VERSION 0x02
|
||||
#define PAR_EMULATOR_MODE 0x03
|
||||
# define EMULATOR_MODE_DEBUGWIRE 0x00
|
||||
# define EMULATOR_MODE_JTAG 0x01
|
||||
# define EMULATOR_MODE_HV 0x02 /* HVSP or PP mode of AVR Dragon */
|
||||
# define EMULATOR_MODE_SPI 0x03
|
||||
# define EMULATOR_MODE_JTAG_AVR32 0x04
|
||||
# define EMULATOR_MODE_JTAG_XMEGA 0x05
|
||||
# define EMULATOR_MODE_PDI 0x06
|
||||
#define PAR_IREG 0x04
|
||||
#define PAR_BAUD_RATE 0x05
|
||||
# define PAR_BAUD_2400 0x01
|
||||
# define PAR_BAUD_4800 0x02
|
||||
# define PAR_BAUD_9600 0x03
|
||||
# define PAR_BAUD_19200 0x04 /* default */
|
||||
# define PAR_BAUD_38400 0x05
|
||||
# define PAR_BAUD_57600 0x06
|
||||
# define PAR_BAUD_115200 0x07
|
||||
# define PAR_BAUD_14400 0x08
|
||||
#define PAR_OCD_VTARGET 0x06
|
||||
#define PAR_OCD_JTAG_CLK 0x07
|
||||
#define PAR_OCD_BREAK_CAUSE 0x08
|
||||
#define PAR_TIMERS_RUNNING 0x09
|
||||
#define PAR_BREAK_ON_CHANGE_FLOW 0x0A
|
||||
#define PAR_BREAK_ADDR1 0x0B
|
||||
#define PAR_BREAK_ADDR2 0x0C
|
||||
#define PAR_COMBBREAKCTRL 0x0D
|
||||
#define PAR_JTAGID 0x0E
|
||||
#define PAR_UNITS_BEFORE 0x0F
|
||||
#define PAR_UNITS_AFTER 0x10
|
||||
#define PAR_BIT_BEFORE 0x11
|
||||
#define PAR_BIT_ATER 0x12
|
||||
#define PAR_EXTERNAL_RESET 0x13
|
||||
#define PAR_FLASH_PAGE_SIZE 0x14
|
||||
#define PAR_EEPROM_PAGE_SIZE 0x15
|
||||
#define PAR_UNUSED1 0x16
|
||||
#define PAR_PSB0 0x17
|
||||
#define PAR_PSB1 0x18
|
||||
#define PAR_PROTOCOL_DEBUG_EVENT 0x19
|
||||
#define PAR_MCU_STATE 0x1A
|
||||
# define STOPPED 0x00
|
||||
# define RUNNING 0x01
|
||||
# define PROGRAMMING 0x02
|
||||
#define PAR_DAISY_CHAIN_INFO 0x1B
|
||||
#define PAR_BOOT_ADDRESS 0x1C
|
||||
#define PAR_TARGET_SIGNATURE 0x1D
|
||||
#define PAR_DEBUGWIRE_BAUDRATE 0x1E
|
||||
#define PAR_PROGRAM_ENTRY_POINT 0x1F
|
||||
#define PAR_PDI_OFFSET_START 0x32
|
||||
#define PAR_PDI_OFFSET_END 0x33
|
||||
#define PAR_PACKET_PARSING_ERRORS 0x40
|
||||
#define PAR_VALID_PACKETS_RECEIVED 0x41
|
||||
#define PAR_INTERCOMMUNICATION_TX_FAILURES 0x42
|
||||
#define PAR_INTERCOMMUNICATION_RX_FAILURES 0x43
|
||||
#define PAR_CRC_ERRORS 0x44
|
||||
#define PAR_POWER_SOURCE 0x45
|
||||
# define POWER_EXTERNAL 0x00
|
||||
# define POWER_USB 0x01
|
||||
#define PAR_CAN_FLAG 0x22
|
||||
# define DONT_READ_CAN_MAILBOX 0x00
|
||||
# define READ_CAN_MAILBOX 0x01
|
||||
#define PAR_ENABLE_IDR_IN_RUN_MODE 0x23
|
||||
# define ACCESS_OSCCAL 0x00
|
||||
# define ACCESS_IDR 0x01
|
||||
#define PAR_ALLOW_PAGEPROGRAMMING_IN_SCANCHAIN 0x24
|
||||
# define PAGEPROG_NOT_ALLOWED 0x00
|
||||
# define PAGEPROG_ALLOWED 0x01
|
||||
|
||||
/* Xmega erase memory types, for CMND_XMEGA_ERASE */
|
||||
#define XMEGA_ERASE_CHIP 0x00
|
||||
#define XMEGA_ERASE_APP 0x01
|
||||
#define XMEGA_ERASE_BOOT 0x02
|
||||
#define XMEGA_ERASE_EEPROM 0x03
|
||||
#define XMEGA_ERASE_APP_PAGE 0x04
|
||||
#define XMEGA_ERASE_BOOT_PAGE 0x05
|
||||
#define XMEGA_ERASE_EEPROM_PAGE 0x06
|
||||
#define XMEGA_ERASE_USERSIG 0x07
|
||||
|
||||
/* AVR32 related definitions */
|
||||
#define AVR32_FLASHC_FCR 0xFFFE1400
|
||||
#define AVR32_FLASHC_FCMD 0xFFFE1404
|
||||
#define AVR32_FLASHC_FCMD_KEY 0xA5000000
|
||||
#define AVR32_FLASHC_FCMD_WRITE_PAGE 1
|
||||
#define AVR32_FLASHC_FCMD_ERASE_PAGE 2
|
||||
#define AVR32_FLASHC_FCMD_CLEAR_PAGE_BUFFER 3
|
||||
#define AVR32_FLASHC_FCMD_LOCK 4
|
||||
#define AVR32_FLASHC_FCMD_UNLOCK 5
|
||||
#define AVR32_FLASHC_FSR 0xFFFE1408
|
||||
#define AVR32_FLASHC_FSR_RDY 0x00000001
|
||||
#define AVR32_FLASHC_FSR_ERR 0x00000008
|
||||
#define AVR32_FLASHC_FGPFRHI 0xFFFE140C
|
||||
#define AVR32_FLASHC_FGPFRLO 0xFFFE1410
|
||||
|
||||
#define AVR32_DC 0x00000008
|
||||
#define AVR32_DS 0x00000010
|
||||
#define AVR32_DINST 0x00000104
|
||||
#define AVR32_DCCPU 0x00000110
|
||||
#define AVR32_DCEMU 0x00000114
|
||||
#define AVR32_DCSR 0x00000118
|
||||
|
||||
#define AVR32_DC_ABORT 0x80000000
|
||||
#define AVR32_DC_RESET 0x40000000
|
||||
#define AVR32_DC_DBE 0x00002000
|
||||
#define AVR32_DC_DBR 0x00001000
|
||||
|
||||
#define AVR32_RESET_READ 0x0001
|
||||
#define AVR32_RESET_WRITE 0x0002
|
||||
#define AVR32_RESET_CHIP_ERASE 0x0004
|
||||
#define AVR32_SET4RUNNING 0x0008
|
||||
//#define AVR32_RESET_COMMON (AVR32_RESET_READ | AVR32_RESET_WRITE | AVR32_RESET_CHIP_ERASE )
|
||||
|
||||
|
||||
#if !defined(JTAGMKII_PRIVATE_EXPORTED)
|
||||
/*
|
||||
* In appnote AVR067, struct device_descriptor is written with
|
||||
* int/long field types. We cannot use them directly, as they were
|
||||
* neither properly aligned for portability, nor did they care for
|
||||
* endianess issues. We thus use arrays of unsigned chars, plus
|
||||
* conversion macros.
|
||||
*/
|
||||
struct device_descriptor
|
||||
{
|
||||
unsigned char ucReadIO[8]; /*LSB = IOloc 0, MSB = IOloc63 */
|
||||
unsigned char ucReadIOShadow[8]; /*LSB = IOloc 0, MSB = IOloc63 */
|
||||
unsigned char ucWriteIO[8]; /*LSB = IOloc 0, MSB = IOloc63 */
|
||||
unsigned char ucWriteIOShadow[8]; /*LSB = IOloc 0, MSB = IOloc63 */
|
||||
unsigned char ucReadExtIO[52]; /*LSB = IOloc 96, MSB = IOloc511 */
|
||||
unsigned char ucReadIOExtShadow[52]; /*LSB = IOloc 96, MSB = IOloc511 */
|
||||
unsigned char ucWriteExtIO[52]; /*LSB = IOloc 96, MSB = IOloc511 */
|
||||
unsigned char ucWriteIOExtShadow[52];/*LSB = IOloc 96, MSB = IOloc511 */
|
||||
unsigned char ucIDRAddress; /*IDR address */
|
||||
unsigned char ucSPMCRAddress; /*SPMCR Register address and dW BasePC */
|
||||
unsigned char ucRAMPZAddress; /*RAMPZ Register address in SRAM I/O */
|
||||
/*space */
|
||||
unsigned char uiFlashPageSize[2]; /*Device Flash Page Size, Size = */
|
||||
/*2 exp ucFlashPageSize */
|
||||
unsigned char ucEepromPageSize; /*Device Eeprom Page Size in bytes */
|
||||
unsigned char ulBootAddress[4]; /*Device Boot Loader Start Address */
|
||||
unsigned char uiUpperExtIOLoc[2]; /*Topmost (last) extended I/O */
|
||||
/*location, 0 if no external I/O */
|
||||
unsigned char ulFlashSize[4]; /*Device Flash Size */
|
||||
unsigned char ucEepromInst[20]; /*Instructions for W/R EEPROM */
|
||||
unsigned char ucFlashInst[3]; /*Instructions for W/R FLASH */
|
||||
unsigned char ucSPHaddr; /* stack pointer high */
|
||||
unsigned char ucSPLaddr; /* stack pointer low */
|
||||
/* new as of 16-02-2004 */
|
||||
unsigned char uiFlashpages[2]; /* number of pages in flash */
|
||||
unsigned char ucDWDRAddress; /* DWDR register address */
|
||||
unsigned char ucDWBasePC; /* base/mask value of the PC */
|
||||
/* new as of 30-04-2004 */
|
||||
unsigned char ucAllowFullPageBitstream; /* FALSE on ALL new */
|
||||
/*parts */
|
||||
unsigned char uiStartSmallestBootLoaderSection[2]; /* */
|
||||
/* new as of 18-10-2004 */
|
||||
unsigned char EnablePageProgramming; /* For JTAG parts only, */
|
||||
/* default TRUE */
|
||||
unsigned char ucCacheType; /* CacheType_Normal 0x00, */
|
||||
/* CacheType_CAN 0x01, */
|
||||
/* CacheType_HEIMDALL 0x02 */
|
||||
/* new as of 27-10-2004 */
|
||||
unsigned char uiSramStartAddr[2]; /* Start of SRAM */
|
||||
unsigned char ucResetType; /* Selects reset type. ResetNormal = 0x00 */
|
||||
/* ResetAT76CXXX = 0x01 */
|
||||
unsigned char ucPCMaskExtended; /* For parts with extended PC */
|
||||
unsigned char ucPCMaskHigh; /* PC high mask */
|
||||
unsigned char ucEindAddress; /* Selects reset type. [EIND address...] */
|
||||
/* new as of early 2005, firmware 4.x */
|
||||
unsigned char EECRAddress[2]; /* EECR memory-mapped IO address */
|
||||
};
|
||||
|
||||
/* New Xmega device descriptor, for firmware version 7 and above */
|
||||
struct xmega_device_desc {
|
||||
unsigned char whatever[2]; // cannot guess; must be 0x0002
|
||||
unsigned char datalen; // length of the following data, = 47
|
||||
unsigned char nvm_app_offset[4]; // NVM offset for application flash
|
||||
unsigned char nvm_boot_offset[4]; // NVM offset for boot flash
|
||||
unsigned char nvm_eeprom_offset[4]; // NVM offset for EEPROM
|
||||
unsigned char nvm_fuse_offset[4]; // NVM offset for fuses
|
||||
unsigned char nvm_lock_offset[4]; // NVM offset for lock bits
|
||||
unsigned char nvm_user_sig_offset[4]; // NVM offset for user signature row
|
||||
unsigned char nvm_prod_sig_offset[4]; // NVM offset for production sign. row
|
||||
unsigned char nvm_data_offset[4]; // NVM offset for data memory (SRAM + IO)
|
||||
unsigned char app_size[4]; // size of application flash
|
||||
unsigned char boot_size[2]; // size of boot flash
|
||||
unsigned char flash_page_size[2]; // flash page size
|
||||
unsigned char eeprom_size[2]; // size of EEPROM
|
||||
unsigned char eeprom_page_size; // EEPROM page size
|
||||
unsigned char nvm_base_addr[2]; // IO space base address of NVM controller
|
||||
unsigned char mcu_base_addr[2]; // IO space base address of MCU control
|
||||
};
|
||||
#endif /* JTAGMKII_PRIVATE_EXPORTED */
|
||||
|
||||
/* return code from jtagmkII_getsync() to indicate a "graceful"
|
||||
* failure, i.e. an attempt to enable ISP failed and should be
|
||||
* eventually retried */
|
||||
#define JTAGII_GETSYNC_FAIL_GRACEFUL (-2)
|
||||
168
src/jtagmkI_private.h
Normal file
168
src/jtagmkI_private.h
Normal file
@@ -0,0 +1,168 @@
|
||||
/*
|
||||
* avrdude - A Downloader/Uploader for AVR device programmers
|
||||
* Copyright (C) 2005 Joerg Wunsch <j@uriah.heep.sax.de>
|
||||
*
|
||||
*
|
||||
* 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/* $Id$ */
|
||||
|
||||
|
||||
/*
|
||||
* JTAG ICE mkI definitions
|
||||
*/
|
||||
|
||||
/* ICE command codes */
|
||||
/* 0x20 Get Synch [Resp_OK] */
|
||||
#define CMD_GET_SYNC ' '
|
||||
|
||||
/* 0x31 Single Step [Sync_CRC/EOP] [Resp_OK] */
|
||||
/* 0x32 Read PC [Sync_CRC/EOP] [Resp_OK] [program counter]
|
||||
* [Resp_OK] */
|
||||
/* 0x33 Write PC [program counter] [Sync_CRC/EOP] [Resp_OK]
|
||||
* [Resp_OK] */
|
||||
/* 0xA2 Firmware Upgrade [upgrade string] [Sync_CRC/EOP] [Resp_OK]
|
||||
* [Resp_OK] */
|
||||
/* 0xA0 Set Device Descriptor [device info] [Sync_CRC/EOP] [Resp_OK]
|
||||
* [Resp_OK] */
|
||||
#define CMD_SET_DEVICE_DESCRIPTOR 0xA0
|
||||
|
||||
/* 0x42 Set Parameter [parameter] [setting] [Sync_CRC/EOP] [Resp_OK]
|
||||
* [Resp_OK] */
|
||||
#define CMD_SET_PARAM 'B'
|
||||
|
||||
/* 0x46 Forced Stop [Sync_CRC/EOP] [Resp_OK] [checksum][program
|
||||
* counter] [Resp_OK] */
|
||||
#define CMD_STOP 'F'
|
||||
|
||||
/* 0x47 Go [Sync_CRC/EOP] [Resp_OK] */
|
||||
#define CMD_GO 'G'
|
||||
|
||||
/* 0x52 Read Memory [memory type] [word count] [start address]
|
||||
* [Sync_CRC/EOP] [Resp_OK] [word 0] ... [word n] [checksum]
|
||||
* [Resp_OK] */
|
||||
#define CMD_READ_MEM 'R'
|
||||
|
||||
/* 0x53 Get Sign On [Sync_CRC/EOP] [Resp_OK] ["AVRNOCD"] [Resp_OK] */
|
||||
#define CMD_GET_SIGNON 'S'
|
||||
|
||||
/* 0XA1 Erase Page spm [address] [Sync_CRC/EOP] [Resp_OK] [Resp_OK] */
|
||||
|
||||
/* 0x57 Write Memory [memory type] [word count] [start address]
|
||||
* [Sync_CRC/EOP] [Resp_OK] [Cmd_DATA] [word 0] ... [word n] */
|
||||
#define CMD_WRITE_MEM 'W'
|
||||
|
||||
/* Second half of write memory: the data command. Undocumented. */
|
||||
#define CMD_DATA 'h'
|
||||
|
||||
/* 0x64 Get Debug Info [Sync_CRC/EOP] [Resp_OK] [0x00] [Resp_OK] */
|
||||
/* 0x71 Get Parameter [parameter] [Sync_CRC/EOP] [Resp_OK] [setting]
|
||||
* [Resp_OK] */
|
||||
#define CMD_GET_PARAM 'q'
|
||||
|
||||
/* 0x78 Reset [Sync_CRC/EOP] [Resp_OK] [Resp_OK] */
|
||||
#define CMD_RESET 'x'
|
||||
|
||||
/* 0xA3 Enter Progmode [Sync_CRC/EOP] [Resp_OK] [Resp_OK] */
|
||||
#define CMD_ENTER_PROGMODE 0xa3
|
||||
|
||||
/* 0xA4 Leave Progmode [Sync_CRC/EOP] [Resp_OK] [Resp_OK] */
|
||||
#define CMD_LEAVE_PROGMODE 0xa4
|
||||
|
||||
/* 0xA5 Chip Erase [Sync_CRC/EOP] [Resp_OK] [Resp_OK] */
|
||||
#define CMD_CHIP_ERASE 0xa5
|
||||
|
||||
|
||||
/* ICE responses */
|
||||
#define RESP_OK 'A'
|
||||
#define RESP_BREAK 'B'
|
||||
#define RESP_INFO 'G'
|
||||
#define RESP_FAILED 'F'
|
||||
#define RESP_SYNC_ERROR 'E'
|
||||
#define RESP_SLEEP 'H'
|
||||
#define RESP_POWER 'I'
|
||||
|
||||
#define PARM_BITRATE 'b'
|
||||
#define PARM_SW_VERSION 0x7b
|
||||
#define PARM_HW_VERSION 0x7a
|
||||
#define PARM_IREG_HIGH 0x81
|
||||
#define PARM_IREG_LOW 0x82
|
||||
#define PARM_OCD_VTARGET 0x84
|
||||
#define PARM_OCD_BREAK_CAUSE 0x85
|
||||
#define PARM_CLOCK 0x86
|
||||
#define PARM_EXTERNAL_RESET 0x8b
|
||||
#define PARM_FLASH_PAGESIZE_LOW 0x88
|
||||
#define PARM_FLASH_PAGESIZE_HIGH 0x89
|
||||
#define PARM_EEPROM_PAGESIZE 0x8a
|
||||
#define PARM_TIMERS_RUNNING 0xa0
|
||||
#define PARM_BP_FLOW 0xa1
|
||||
#define PARM_BP_X_HIGH 0xa2
|
||||
#define PARM_BP_X_LOW 0xa3
|
||||
#define PARM_BP_Y_HIGH 0xa4
|
||||
#define PARM_BP_Y_LOW 0xa5
|
||||
#define PARM_BP_MODE 0xa6
|
||||
#define PARM_JTAGID_BYTE0 0xa7
|
||||
#define PARM_JTAGID_BYTE1 0xa8
|
||||
#define PARM_JTAGID_BYTE2 0xa9
|
||||
#define PARM_JTAGID_BYTE3 0xaa
|
||||
#define PARM_UNITS_BEFORE 0xab
|
||||
#define PARM_UNITS_AFTER 0xac
|
||||
#define PARM_BIT_BEFORE 0xad
|
||||
#define PARM_BIT_AFTER 0xae
|
||||
#define PARM_PSB0_LOW 0xaf
|
||||
#define PARM_PSBO_HIGH 0xb0
|
||||
#define PARM_PSB1_LOW 0xb1
|
||||
#define PARM_PSB1_HIGH 0xb2
|
||||
#define PARM_MCU_MODE 0xb3
|
||||
|
||||
#define JTAG_BITRATE_1_MHz 0xff
|
||||
#define JTAG_BITRATE_500_kHz 0xfe
|
||||
#define JTAG_BITRATE_250_kHz 0xfd
|
||||
#define JTAG_BITRATE_125_kHz 0xfb
|
||||
|
||||
/* memory types for CMND_{READ,WRITE}_MEMORY */
|
||||
#define MTYPE_IO_SHADOW 0x30 /* cached IO registers? */
|
||||
#define MTYPE_SRAM 0x20 /* target's SRAM or [ext.] IO registers */
|
||||
#define MTYPE_EEPROM 0x22 /* EEPROM, what way? */
|
||||
#define MTYPE_EVENT 0x60 /* ICE event memory */
|
||||
#define MTYPE_SPM 0xA0 /* flash through LPM/SPM */
|
||||
#define MTYPE_FLASH_PAGE 0xB0 /* flash in programming mode */
|
||||
#define MTYPE_EEPROM_PAGE 0xB1 /* EEPROM in programming mode */
|
||||
#define MTYPE_FUSE_BITS 0xB2 /* fuse bits in programming mode */
|
||||
#define MTYPE_LOCK_BITS 0xB3 /* lock bits in programming mode */
|
||||
#define MTYPE_SIGN_JTAG 0xB4 /* signature in programming mode */
|
||||
#define MTYPE_OSCCAL_BYTE 0xB5 /* osccal cells in programming mode */
|
||||
|
||||
struct device_descriptor
|
||||
{
|
||||
unsigned char ucReadIO[8]; /*LSB = IOloc 0, MSB = IOloc63 */
|
||||
unsigned char ucWriteIO[8]; /*LSB = IOloc 0, MSB = IOloc63 */
|
||||
unsigned char ucReadIOShadow[8]; /*LSB = IOloc 0, MSB = IOloc63 */
|
||||
unsigned char ucWriteIOShadow[8]; /*LSB = IOloc 0, MSB = IOloc63 */
|
||||
unsigned char ucReadExtIO[20]; /*LSB = IOloc 96, MSB = IOloc255 */
|
||||
unsigned char ucWriteExtIO[20]; /*LSB = IOloc 96, MSB = IOloc255 */
|
||||
unsigned char ucReadIOExtShadow[20]; /*LSB = IOloc 96, MSB = IOloc255 */
|
||||
unsigned char ucWriteIOExtShadow[20];/*LSB = IOloc 96, MSB = IOloc255 */
|
||||
unsigned char ucIDRAddress; /*IDR address */
|
||||
unsigned char ucSPMCRAddress; /*SPMCR Register address and dW BasePC */
|
||||
unsigned char ucRAMPZAddress; /*RAMPZ Register address in SRAM I/O */
|
||||
/*space */
|
||||
unsigned char uiFlashPageSize[2]; /*Device Flash Page Size, Size = */
|
||||
/*2 exp ucFlashPageSize */
|
||||
unsigned char ucEepromPageSize; /*Device Eeprom Page Size in bytes */
|
||||
unsigned char ulBootAddress[4]; /*Device Boot Loader Start Address */
|
||||
unsigned char uiUpperExtIOLoc; /*Topmost (last) extended I/O */
|
||||
/*location, 0 if no external I/O */
|
||||
};
|
||||
265
src/lexer.l
Normal file
265
src/lexer.l
Normal file
@@ -0,0 +1,265 @@
|
||||
/*
|
||||
* avrdude - A Downloader/Uploader for AVR device programmers
|
||||
* Copyright (C) 2000-2004 Brian S. Dean <bsd@bsdhome.com>
|
||||
* Copyright (C) 2006 Joerg Wunsch <j@uriah.heep.sax.de>
|
||||
*
|
||||
* 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/* $Id$ */
|
||||
|
||||
%{
|
||||
/* need this for the call to atof() below */
|
||||
#include <math.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <limits.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include "avrdude.h"
|
||||
#include "libavrdude.h"
|
||||
#include "config.h"
|
||||
|
||||
#include "config_gram.h"
|
||||
|
||||
#ifndef YYERRCODE
|
||||
#define YYERRCODE 256
|
||||
#endif
|
||||
|
||||
%}
|
||||
|
||||
DIGIT [0-9]
|
||||
HEXDIGIT [0-9a-fA-F]
|
||||
SIGN [+-]
|
||||
|
||||
%x strng
|
||||
%x incl
|
||||
%x comment
|
||||
%option nounput
|
||||
|
||||
/* Bump resources for classic lex. */
|
||||
%e2000
|
||||
%p10000
|
||||
%n1000
|
||||
|
||||
%%
|
||||
|
||||
#{SIGN}*{DIGIT}+ { yylval = number(yytext); return TKN_NUMBER; }
|
||||
#{SIGN}*{DIGIT}+"."{DIGIT}* { yylval = number_real(yytext); return TKN_NUMBER_REAL; }
|
||||
#{SIGN}*"."{DIGIT}* { yylval = number_real(yytext); return TKN_NUMBER_REAL; }
|
||||
{DIGIT}+ { yylval = number(yytext); return TKN_NUMBER; }
|
||||
{DIGIT}+"."{DIGIT}* { yylval = number_real(yytext); return TKN_NUMBER_REAL; }
|
||||
"."{DIGIT}+ { yylval = number_real(yytext); return TKN_NUMBER_REAL; }
|
||||
|
||||
"\"" { string_buf_ptr = string_buf; BEGIN(strng); }
|
||||
|
||||
0x{HEXDIGIT}+ { yylval = hexnumber(yytext); return TKN_NUMBER; }
|
||||
|
||||
|
||||
|
||||
# { /* The following eats '#' style comments to end of line */
|
||||
BEGIN(comment); }
|
||||
<comment>[^\n] { /* eat comments */ }
|
||||
<comment>\n { lineno++; BEGIN(INITIAL); }
|
||||
|
||||
|
||||
"/*" { /* The following eats multiline C style comments */
|
||||
int c;
|
||||
int comment_start;
|
||||
|
||||
comment_start = lineno;
|
||||
while (1) {
|
||||
while (((c = input()) != '*') && (c != EOF)) {
|
||||
/* eat up text of comment, but keep counting lines */
|
||||
if (c == '\n')
|
||||
lineno++;
|
||||
}
|
||||
|
||||
if (c == '*') {
|
||||
while ((c = input()) == '*')
|
||||
;
|
||||
if (c == '/')
|
||||
break; /* found the end */
|
||||
}
|
||||
|
||||
if (c == EOF) {
|
||||
yyerror("EOF in comment (started on line %d)", comment_start);
|
||||
return YYERRCODE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
<strng>\" { *string_buf_ptr = 0; string_buf_ptr = string_buf;
|
||||
yylval = string(string_buf_ptr); BEGIN(INITIAL); return TKN_STRING; }
|
||||
<strng>\\n *string_buf_ptr++ = '\n';
|
||||
<strng>\\t *string_buf_ptr++ = '\t';
|
||||
<strng>\\r *string_buf_ptr++ = '\r';
|
||||
<strng>\\b *string_buf_ptr++ = '\b';
|
||||
<strng>\\f *string_buf_ptr++ = '\f';
|
||||
<strng>\\(.|\n) *(string_buf_ptr++) = yytext[1];
|
||||
<strng>[^\\\n\"]+ { char *yptr = yytext; while (*yptr)
|
||||
*(string_buf_ptr++) = *(yptr++); }
|
||||
|
||||
<strng>\n { yyerror("unterminated character constant");
|
||||
return YYERRCODE; }
|
||||
|
||||
allowfullpagebitstream { yylval=NULL; return K_ALLOWFULLPAGEBITSTREAM; }
|
||||
avr910_devcode { yylval=NULL; return K_AVR910_DEVCODE; }
|
||||
bank_size { yylval=NULL; return K_PAGE_SIZE; }
|
||||
banked { yylval=NULL; return K_PAGED; }
|
||||
baudrate { yylval=NULL; return K_BAUDRATE; }
|
||||
blocksize { yylval=NULL; return K_BLOCKSIZE; }
|
||||
bs2 { yylval=NULL; return K_BS2; }
|
||||
buff { yylval=NULL; return K_BUFF; }
|
||||
bytedelay { yylval=NULL; return K_BYTEDELAY; }
|
||||
chip_erase { yylval=new_token(K_CHIP_ERASE); return K_CHIP_ERASE; }
|
||||
chip_erase_delay { yylval=NULL; return K_CHIP_ERASE_DELAY; }
|
||||
chiperasepolltimeout { yylval=NULL; return K_CHIPERASEPOLLTIMEOUT; }
|
||||
chiperasepulsewidth { yylval=NULL; return K_CHIPERASEPULSEWIDTH; }
|
||||
chiperasetime { yylval=NULL; return K_CHIPERASETIME; }
|
||||
cmdexedelay { yylval=NULL; return K_CMDEXEDELAY; }
|
||||
connection_type { yylval=NULL; return K_CONNTYPE; }
|
||||
dedicated { yylval=new_token(K_DEDICATED); return K_DEDICATED; }
|
||||
default_bitclock { yylval=NULL; return K_DEFAULT_BITCLOCK; }
|
||||
default_parallel { yylval=NULL; return K_DEFAULT_PARALLEL; }
|
||||
default_programmer { yylval=NULL; return K_DEFAULT_PROGRAMMER; }
|
||||
default_safemode { yylval=NULL; return K_DEFAULT_SAFEMODE; }
|
||||
default_serial { yylval=NULL; return K_DEFAULT_SERIAL; }
|
||||
delay { yylval=NULL; return K_DELAY; }
|
||||
desc { yylval=NULL; return K_DESC; }
|
||||
family_id { yylval=NULL; return K_FAMILY_ID; }
|
||||
devicecode { yylval=NULL; return K_DEVICECODE; }
|
||||
eecr { yylval=NULL; return K_EECR; }
|
||||
eeprom { yylval=NULL; return K_EEPROM; }
|
||||
eeprom_instr { yylval=NULL; return K_EEPROM_INSTR; }
|
||||
enablepageprogramming { yylval=NULL; return K_ENABLEPAGEPROGRAMMING; }
|
||||
errled { yylval=NULL; return K_ERRLED; }
|
||||
flash { yylval=NULL; return K_FLASH; }
|
||||
flash_instr { yylval=NULL; return K_FLASH_INSTR; }
|
||||
has_debugwire { yylval=NULL; return K_HAS_DW; }
|
||||
has_jtag { yylval=NULL; return K_HAS_JTAG; }
|
||||
has_pdi { yylval=NULL; return K_HAS_PDI; }
|
||||
has_tpi { yylval=NULL; return K_HAS_TPI; }
|
||||
has_updi { yylval=NULL; return K_HAS_UPDI; }
|
||||
hventerstabdelay { yylval=NULL; return K_HVENTERSTABDELAY; }
|
||||
hvleavestabdelay { yylval=NULL; return K_HVLEAVESTABDELAY; }
|
||||
hvsp_controlstack { yylval=NULL; return K_HVSP_CONTROLSTACK; }
|
||||
hvspcmdexedelay { yylval=NULL; return K_HVSPCMDEXEDELAY; }
|
||||
id { yylval=NULL; return K_ID; }
|
||||
idr { yylval=NULL; return K_IDR; }
|
||||
io { yylval=new_token(K_IO); return K_IO; }
|
||||
is_at90s1200 { yylval=NULL; return K_IS_AT90S1200; }
|
||||
is_avr32 { yylval=NULL; return K_IS_AVR32; }
|
||||
latchcycles { yylval=NULL; return K_LATCHCYCLES; }
|
||||
load_ext_addr { yylval=new_token(K_LOAD_EXT_ADDR); return K_LOAD_EXT_ADDR; }
|
||||
loadpage_hi { yylval=new_token(K_LOADPAGE_HI); return K_LOADPAGE_HI; }
|
||||
loadpage_lo { yylval=new_token(K_LOADPAGE_LO); return K_LOADPAGE_LO; }
|
||||
max_write_delay { yylval=NULL; return K_MAX_WRITE_DELAY; }
|
||||
mcu_base { yylval=NULL; return K_MCU_BASE; }
|
||||
memory { yylval=NULL; return K_MEMORY; }
|
||||
min_write_delay { yylval=NULL; return K_MIN_WRITE_DELAY; }
|
||||
miso { yylval=NULL; return K_MISO; }
|
||||
mode { yylval=NULL; return K_MODE; }
|
||||
mosi { yylval=NULL; return K_MOSI; }
|
||||
no { yylval=new_token(K_NO); return K_NO; }
|
||||
num_banks { yylval=NULL; return K_NUM_PAGES; }
|
||||
num_pages { yylval=NULL; return K_NUM_PAGES; }
|
||||
nvm_base { yylval=NULL; return K_NVM_BASE; }
|
||||
ocd_base { yylval=NULL; return K_OCD_BASE; }
|
||||
ocdrev { yylval=NULL; return K_OCDREV; }
|
||||
offset { yylval=NULL; return K_OFFSET; }
|
||||
page_size { yylval=NULL; return K_PAGE_SIZE; }
|
||||
paged { yylval=NULL; return K_PAGED; }
|
||||
pagel { yylval=NULL; return K_PAGEL; }
|
||||
parallel { yylval=NULL; return K_PARALLEL; }
|
||||
parent { yylval=NULL; return K_PARENT; }
|
||||
part { yylval=NULL; return K_PART; }
|
||||
pgm_enable { yylval=new_token(K_PGM_ENABLE); return K_PGM_ENABLE; }
|
||||
pgmled { yylval=NULL; return K_PGMLED; }
|
||||
pollindex { yylval=NULL; return K_POLLINDEX; }
|
||||
pollmethod { yylval=NULL; return K_POLLMETHOD; }
|
||||
pollvalue { yylval=NULL; return K_POLLVALUE; }
|
||||
postdelay { yylval=NULL; return K_POSTDELAY; }
|
||||
poweroffdelay { yylval=NULL; return K_POWEROFFDELAY; }
|
||||
pp_controlstack { yylval=NULL; return K_PP_CONTROLSTACK; }
|
||||
predelay { yylval=NULL; return K_PREDELAY; }
|
||||
progmodedelay { yylval=NULL; return K_PROGMODEDELAY; }
|
||||
programfusepolltimeout { yylval=NULL; return K_PROGRAMFUSEPOLLTIMEOUT; }
|
||||
programfusepulsewidth { yylval=NULL; return K_PROGRAMFUSEPULSEWIDTH; }
|
||||
programlockpolltimeout { yylval=NULL; return K_PROGRAMLOCKPOLLTIMEOUT; }
|
||||
programlockpulsewidth { yylval=NULL; return K_PROGRAMLOCKPULSEWIDTH; }
|
||||
programmer { yylval=NULL; return K_PROGRAMMER; }
|
||||
pseudo { yylval=new_token(K_PSEUDO); return K_PSEUDO; }
|
||||
pwroff_after_write { yylval=NULL; return K_PWROFF_AFTER_WRITE; }
|
||||
rampz { yylval=NULL; return K_RAMPZ; }
|
||||
rdyled { yylval=NULL; return K_RDYLED; }
|
||||
read { yylval=new_token(K_READ); return K_READ; }
|
||||
read_hi { yylval=new_token(K_READ_HI); return K_READ_HI; }
|
||||
read_lo { yylval=new_token(K_READ_LO); return K_READ_LO; }
|
||||
readback_p1 { yylval=NULL; return K_READBACK_P1; }
|
||||
readback_p2 { yylval=NULL; return K_READBACK_P2; }
|
||||
readsize { yylval=NULL; return K_READSIZE; }
|
||||
reset { yylval=new_token(K_RESET); return K_RESET; }
|
||||
resetdelay { yylval=NULL; return K_RESETDELAY; }
|
||||
resetdelayms { yylval=NULL; return K_RESETDELAYMS; }
|
||||
resetdelayus { yylval=NULL; return K_RESETDELAYUS; }
|
||||
retry_pulse { yylval=NULL; return K_RETRY_PULSE; }
|
||||
sck { yylval=new_token(K_SCK); return K_SCK; }
|
||||
serial { yylval=NULL; return K_SERIAL; }
|
||||
signature { yylval=NULL; return K_SIGNATURE; }
|
||||
size { yylval=NULL; return K_SIZE; }
|
||||
spmcr { yylval=NULL; return K_SPMCR; }
|
||||
stabdelay { yylval=NULL; return K_STABDELAY; }
|
||||
stk500_devcode { yylval=NULL; return K_STK500_DEVCODE; }
|
||||
synchcycles { yylval=NULL; return K_SYNCHCYCLES; }
|
||||
synchloops { yylval=NULL; return K_SYNCHLOOPS; }
|
||||
timeout { yylval=NULL; return K_TIMEOUT; }
|
||||
togglevtg { yylval=NULL; return K_TOGGLEVTG; }
|
||||
type { yylval=NULL; return K_TYPE; }
|
||||
usb { yylval=NULL; return K_USB; }
|
||||
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; }
|
||||
write { yylval=new_token(K_WRITE); return K_WRITE; }
|
||||
write_hi { yylval=new_token(K_WRITE_HI); return K_WRITE_HI; }
|
||||
write_lo { yylval=new_token(K_WRITE_LO); return K_WRITE_LO; }
|
||||
writepage { yylval=new_token(K_WRITEPAGE); return K_WRITEPAGE; }
|
||||
yes { yylval=new_token(K_YES); return K_YES; }
|
||||
|
||||
"," { yylval = NULL; pyytext(); return TKN_COMMA; }
|
||||
"=" { yylval = NULL; pyytext(); return TKN_EQUAL; }
|
||||
";" { yylval = NULL; pyytext(); return TKN_SEMI; }
|
||||
"~" { yylval = NULL; pyytext(); return TKN_TILDE; }
|
||||
"(" { yylval = NULL; pyytext(); return TKN_LEFT_PAREN; }
|
||||
")" { yylval = NULL; pyytext(); return TKN_RIGHT_PAREN; }
|
||||
|
||||
"\n" { lineno++; }
|
||||
[ \r\t]+ { /* ignore whitespace */ }
|
||||
|
||||
c: { yyerror("possible old-style config file entry\n"
|
||||
" Update your config file (see " CONFIG_DIR
|
||||
"/avrdude.conf.sample for a sample)");
|
||||
return YYERRCODE; }
|
||||
|
||||
. { return YYERRCODE; }
|
||||
|
||||
%%
|
||||
|
||||
977
src/libavrdude.h
Normal file
977
src/libavrdude.h
Normal file
@@ -0,0 +1,977 @@
|
||||
/*
|
||||
* avrdude - A Downloader/Uploader for AVR device programmers
|
||||
* Copyright (C) Joerg Wunsch
|
||||
*
|
||||
* 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/* $Id$ */
|
||||
|
||||
#ifndef libavrdude_h
|
||||
#define libavrdude_h
|
||||
|
||||
/* XXX should go away */
|
||||
#include "ac_cfg.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <limits.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
/* lets try to select at least 32 bits */
|
||||
#ifdef HAVE_STDINT_H
|
||||
#include <stdint.h>
|
||||
typedef uint32_t pinmask_t;
|
||||
#else
|
||||
#error Need a C99 capable compiler
|
||||
#endif
|
||||
|
||||
|
||||
/* formerly lists.h */
|
||||
|
||||
/*----------------------------------------------------------------------
|
||||
General purpose linked list routines - header file declarations.
|
||||
|
||||
Author : Brian Dean
|
||||
Date : 10 January, 1990
|
||||
----------------------------------------------------------------------*/
|
||||
|
||||
typedef void * LISTID;
|
||||
typedef void * LNODEID;
|
||||
|
||||
|
||||
/*----------------------------------------------------------------------
|
||||
several defines to access the LIST structure as as stack or a queue
|
||||
--- use for program readability
|
||||
----------------------------------------------------------------------*/
|
||||
#define STACKID LISTID
|
||||
#define SNODEID LNODEID
|
||||
#define QUEUEID LISTID
|
||||
#define QNODEID LNODEID
|
||||
|
||||
|
||||
#define PUSH(s,d) lins_n(s,d,1) /* push 'd' onto the stack */
|
||||
#define POP(s) lrmv_n(s,1) /* pop the stack */
|
||||
#define LOOKSTACK(s) lget_n(s,1) /* look at the top of the stack,
|
||||
but don't pop */
|
||||
|
||||
|
||||
#define ENQUEUE(q,d) lins_n(q,d,1) /* put 'd' on the end of the queue */
|
||||
#define DEQUEUE(q) lrmv(q) /* remove next item from the front of
|
||||
the queue */
|
||||
#define REQUEUE(q,d) ladd(q,d) /* re-insert (push) item back on the
|
||||
front of the queue */
|
||||
#define LOOKQUEUE(q) lget(q) /* return next item on the queue,
|
||||
but don't dequeue */
|
||||
#define QUEUELEN(q) lsize(q) /* length of the queue */
|
||||
|
||||
|
||||
#define LISTADD(l,d) ladd(l,d) /* add to end of the list */
|
||||
#define LISTRMV(l,d) lrmv_d(l,d) /* remove from end of the list */
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* .................... Function Prototypes .................... */
|
||||
|
||||
LISTID lcreat ( void * liststruct, int poolsize );
|
||||
void ldestroy ( LISTID lid );
|
||||
void ldestroy_cb ( LISTID lid, void (*ucleanup)(void * data_ptr) );
|
||||
|
||||
LNODEID lfirst ( LISTID ); /* head of the list */
|
||||
LNODEID llast ( LISTID ); /* tail of the list */
|
||||
LNODEID lnext ( LNODEID ); /* next item in the list */
|
||||
LNODEID lprev ( LNODEID ); /* previous item in the list */
|
||||
void * ldata ( LNODEID ); /* data at the current position */
|
||||
int lsize ( LISTID ); /* number of elements in the list */
|
||||
|
||||
int ladd ( LISTID lid, void * p );
|
||||
int laddo ( LISTID lid, void *p,
|
||||
int (*compare)(const void *p1,const void *p2),
|
||||
LNODEID * firstdup );
|
||||
int laddu ( LISTID lid, void * p,
|
||||
int (*compare)(const void *p1,const void *p2));
|
||||
int lins_n ( LISTID lid, void * d, unsigned int n );
|
||||
int lins_ln ( LISTID lid, LNODEID lnid, void * data_ptr );
|
||||
|
||||
void * lget ( LISTID lid );
|
||||
void * lget_n ( LISTID lid, unsigned int n );
|
||||
LNODEID lget_ln ( LISTID lid, unsigned int n );
|
||||
|
||||
void * lrmv ( LISTID lid );
|
||||
void * lrmv_n ( LISTID lid, unsigned int n );
|
||||
void * lrmv_ln ( LISTID lid, LNODEID lnid );
|
||||
void * lrmv_d ( LISTID lid, void * data_ptr );
|
||||
|
||||
LISTID lcat ( LISTID lid1, LISTID lid2 );
|
||||
|
||||
void lsort ( LISTID lid, int (*compare)(void * p1, void * p2));
|
||||
|
||||
void * lsrch ( LISTID lid, void * p, int (*compare)(void *p1,void *p2));
|
||||
|
||||
int lprint ( FILE * f, LISTID lid );
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
/* formerly avrpart.h */
|
||||
|
||||
/*
|
||||
* AVR serial programming instructions
|
||||
*/
|
||||
enum {
|
||||
AVR_OP_READ,
|
||||
AVR_OP_WRITE,
|
||||
AVR_OP_READ_LO,
|
||||
AVR_OP_READ_HI,
|
||||
AVR_OP_WRITE_LO,
|
||||
AVR_OP_WRITE_HI,
|
||||
AVR_OP_LOADPAGE_LO,
|
||||
AVR_OP_LOADPAGE_HI,
|
||||
AVR_OP_LOAD_EXT_ADDR,
|
||||
AVR_OP_WRITEPAGE,
|
||||
AVR_OP_CHIP_ERASE,
|
||||
AVR_OP_PGM_ENABLE,
|
||||
AVR_OP_MAX
|
||||
};
|
||||
|
||||
|
||||
enum {
|
||||
AVR_CMDBIT_IGNORE, /* bit is ignored on input and output */
|
||||
AVR_CMDBIT_VALUE, /* bit is set to 0 or 1 for input or output */
|
||||
AVR_CMDBIT_ADDRESS, /* this bit represents an input address bit */
|
||||
AVR_CMDBIT_INPUT, /* this bit is an input bit */
|
||||
AVR_CMDBIT_OUTPUT /* this bit is an output bit */
|
||||
};
|
||||
|
||||
enum { /* these are assigned to reset_disposition of AVRPART */
|
||||
RESET_DEDICATED, /* reset pin is dedicated */
|
||||
RESET_IO /* reset pin might be configured as an I/O pin */
|
||||
};
|
||||
|
||||
enum ctl_stack_t {
|
||||
CTL_STACK_NONE, /* no control stack defined */
|
||||
CTL_STACK_PP, /* parallel programming control stack */
|
||||
CTL_STACK_HVSP /* high voltage serial programming control stack */
|
||||
};
|
||||
|
||||
/*
|
||||
* serial programming instruction bit specifications
|
||||
*/
|
||||
typedef struct cmdbit {
|
||||
int type; /* AVR_CMDBIT_* */
|
||||
int bitno; /* which input bit to use for this command bit */
|
||||
int value; /* bit value if type == AVR_CMDBIT_VALUD */
|
||||
} CMDBIT;
|
||||
|
||||
typedef struct opcode {
|
||||
CMDBIT bit[32]; /* opcode bit specs */
|
||||
} OPCODE;
|
||||
|
||||
|
||||
#define AVRPART_SERIALOK 0x0001 /* part supports serial programming */
|
||||
#define AVRPART_PARALLELOK 0x0002 /* part supports parallel programming */
|
||||
#define AVRPART_PSEUDOPARALLEL 0x0004 /* part has pseudo parallel support */
|
||||
#define AVRPART_HAS_JTAG 0x0008 /* part has a JTAG i/f */
|
||||
#define AVRPART_ALLOWFULLPAGEBITSTREAM 0x0010 /* JTAG ICE mkII param. */
|
||||
#define AVRPART_ENABLEPAGEPROGRAMMING 0x0020 /* JTAG ICE mkII param. */
|
||||
#define AVRPART_HAS_DW 0x0040 /* part has a debugWire i/f */
|
||||
#define AVRPART_HAS_PDI 0x0080 /* part has PDI i/f rather than ISP (ATxmega) */
|
||||
#define AVRPART_AVR32 0x0100 /* part is in AVR32 family */
|
||||
#define AVRPART_INIT_SMC 0x0200 /* part will undergo chip erase */
|
||||
#define AVRPART_WRITE 0x0400 /* at least one write operation specified */
|
||||
#define AVRPART_HAS_TPI 0x0800 /* part has TPI i/f rather than ISP (ATtiny4/5/9/10) */
|
||||
#define AVRPART_IS_AT90S1200 0x1000 /* part is an AT90S1200 (needs special treatment) */
|
||||
#define AVRPART_HAS_UPDI 0x2000 /* part has UPDI i/f (AVR8X) */
|
||||
|
||||
#define AVR_DESCLEN 64
|
||||
#define AVR_IDLEN 32
|
||||
#define AVR_FAMILYIDLEN 7
|
||||
#define AVR_SIBLEN 16
|
||||
#define CTL_STACK_SIZE 32
|
||||
#define FLASH_INSTR_SIZE 3
|
||||
#define EEPROM_INSTR_SIZE 20
|
||||
|
||||
#define TAG_ALLOCATED 1 /* memory byte is allocated */
|
||||
|
||||
typedef struct avrpart {
|
||||
char desc[AVR_DESCLEN]; /* long part name */
|
||||
char id[AVR_IDLEN]; /* short part name */
|
||||
char family_id[AVR_FAMILYIDLEN+1]; /* family id in the SIB (avr8x) */
|
||||
int stk500_devcode; /* stk500 device code */
|
||||
int avr910_devcode; /* avr910 device code */
|
||||
int chip_erase_delay; /* microseconds */
|
||||
unsigned char pagel; /* for parallel programming */
|
||||
unsigned char bs2; /* for parallel programming */
|
||||
unsigned char signature[3]; /* expected value of signature bytes */
|
||||
unsigned short usbpid; /* USB DFU product ID (0 = none) */
|
||||
int reset_disposition; /* see RESET_ enums */
|
||||
int retry_pulse; /* retry program enable by pulsing
|
||||
this pin (PIN_AVR_*) */
|
||||
unsigned flags; /* see AVRPART_ masks */
|
||||
|
||||
int timeout; /* stk500 v2 xml file parameter */
|
||||
int stabdelay; /* stk500 v2 xml file parameter */
|
||||
int cmdexedelay; /* stk500 v2 xml file parameter */
|
||||
int synchloops; /* stk500 v2 xml file parameter */
|
||||
int bytedelay; /* stk500 v2 xml file parameter */
|
||||
int pollindex; /* stk500 v2 xml file parameter */
|
||||
unsigned char pollvalue; /* stk500 v2 xml file parameter */
|
||||
int predelay; /* stk500 v2 xml file parameter */
|
||||
int postdelay; /* stk500 v2 xml file parameter */
|
||||
int pollmethod; /* stk500 v2 xml file parameter */
|
||||
|
||||
enum ctl_stack_t ctl_stack_type; /* what to use the ctl stack for */
|
||||
unsigned char controlstack[CTL_STACK_SIZE]; /* stk500v2 PP/HVSP ctl stack */
|
||||
unsigned char flash_instr[FLASH_INSTR_SIZE]; /* flash instructions (debugWire, JTAG) */
|
||||
unsigned char eeprom_instr[EEPROM_INSTR_SIZE]; /* EEPROM instructions (debugWire, JTAG) */
|
||||
|
||||
int hventerstabdelay; /* stk500 v2 hv mode parameter */
|
||||
int progmodedelay; /* stk500 v2 hv mode parameter */
|
||||
int latchcycles; /* stk500 v2 hv mode parameter */
|
||||
int togglevtg; /* stk500 v2 hv mode parameter */
|
||||
int poweroffdelay; /* stk500 v2 hv mode parameter */
|
||||
int resetdelayms; /* stk500 v2 hv mode parameter */
|
||||
int resetdelayus; /* stk500 v2 hv mode parameter */
|
||||
int hvleavestabdelay; /* stk500 v2 hv mode parameter */
|
||||
int resetdelay; /* stk500 v2 hv mode parameter */
|
||||
int chiperasepulsewidth; /* stk500 v2 hv mode parameter */
|
||||
int chiperasepolltimeout; /* stk500 v2 hv mode parameter */
|
||||
int chiperasetime; /* stk500 v2 hv mode parameter */
|
||||
int programfusepulsewidth; /* stk500 v2 hv mode parameter */
|
||||
int programfusepolltimeout; /* stk500 v2 hv mode parameter */
|
||||
int programlockpulsewidth; /* stk500 v2 hv mode parameter */
|
||||
int programlockpolltimeout; /* stk500 v2 hv mode parameter */
|
||||
int synchcycles; /* stk500 v2 hv mode parameter */
|
||||
int hvspcmdexedelay; /* stk500 v2 xml file parameter */
|
||||
|
||||
unsigned char idr; /* JTAG ICE mkII XML file parameter */
|
||||
unsigned char rampz; /* JTAG ICE mkII XML file parameter */
|
||||
unsigned char spmcr; /* JTAG ICE mkII XML file parameter */
|
||||
unsigned short eecr; /* JTAC ICE mkII XML file parameter */
|
||||
unsigned int mcu_base; /* Base address of MCU control block in ATxmega devices */
|
||||
unsigned int nvm_base; /* Base address of NVM controller in ATxmega devices */
|
||||
unsigned int ocd_base; /* Base address of OCD module in AVR8X/UPDI devices */
|
||||
int ocdrev; /* OCD revision (JTAGICE3 parameter, from AS6 XML files) */
|
||||
|
||||
OPCODE * op[AVR_OP_MAX]; /* opcodes */
|
||||
|
||||
LISTID mem; /* avr memory definitions */
|
||||
char config_file[PATH_MAX]; /* config file where defined */
|
||||
int lineno; /* config file line number */
|
||||
} AVRPART;
|
||||
|
||||
#define AVR_MEMDESCLEN 64
|
||||
typedef struct avrmem {
|
||||
char desc[AVR_MEMDESCLEN]; /* memory description ("flash", "eeprom", etc) */
|
||||
int paged; /* page addressed (e.g. ATmega flash) */
|
||||
int size; /* total memory size in bytes */
|
||||
int page_size; /* size of memory page (if page addressed) */
|
||||
int num_pages; /* number of pages (if page addressed) */
|
||||
unsigned int offset; /* offset in IO memory (ATxmega) */
|
||||
int min_write_delay; /* microseconds */
|
||||
int max_write_delay; /* microseconds */
|
||||
int pwroff_after_write; /* after this memory type is written to,
|
||||
the device must be powered off and
|
||||
back on, see errata
|
||||
http://www.atmel.com/dyn/resources/prod_documents/doc1280.pdf */
|
||||
unsigned char readback[2]; /* polled read-back values */
|
||||
|
||||
int mode; /* stk500 v2 xml file parameter */
|
||||
int delay; /* stk500 v2 xml file parameter */
|
||||
int blocksize; /* stk500 v2 xml file parameter */
|
||||
int readsize; /* stk500 v2 xml file parameter */
|
||||
int pollindex; /* stk500 v2 xml file parameter */
|
||||
|
||||
unsigned char * buf; /* pointer to memory buffer */
|
||||
unsigned char * tags; /* allocation tags */
|
||||
OPCODE * op[AVR_OP_MAX]; /* opcodes */
|
||||
} AVRMEM;
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* Functions for OPCODE structures */
|
||||
OPCODE * avr_new_opcode(void);
|
||||
void avr_free_opcode(OPCODE * op);
|
||||
int avr_set_bits(OPCODE * op, unsigned char * cmd);
|
||||
int avr_set_addr(OPCODE * op, unsigned char * cmd, unsigned long addr);
|
||||
int avr_set_input(OPCODE * op, unsigned char * cmd, unsigned char data);
|
||||
int avr_get_output(OPCODE * op, unsigned char * res, unsigned char * data);
|
||||
int avr_get_output_index(OPCODE * op);
|
||||
|
||||
/* Functions for AVRMEM structures */
|
||||
AVRMEM * avr_new_memtype(void);
|
||||
int avr_initmem(AVRPART * p);
|
||||
AVRMEM * avr_dup_mem(AVRMEM * m);
|
||||
void avr_free_mem(AVRMEM * m);
|
||||
AVRMEM * avr_locate_mem(AVRPART * p, char * desc);
|
||||
void avr_mem_display(const char * prefix, FILE * f, AVRMEM * m, int type,
|
||||
int verbose);
|
||||
|
||||
/* Functions for AVRPART structures */
|
||||
AVRPART * avr_new_part(void);
|
||||
AVRPART * avr_dup_part(AVRPART * d);
|
||||
void avr_free_part(AVRPART * d);
|
||||
AVRPART * locate_part(LISTID parts, char * partdesc);
|
||||
AVRPART * locate_part_by_avr910_devcode(LISTID parts, int devcode);
|
||||
AVRPART * locate_part_by_signature(LISTID parts, unsigned char * sig,
|
||||
int sigsize);
|
||||
void avr_display(FILE * f, AVRPART * p, const char * prefix, int verbose);
|
||||
|
||||
typedef void (*walk_avrparts_cb)(const char *name, const char *desc,
|
||||
const char *cfgname, int cfglineno,
|
||||
void *cookie);
|
||||
void walk_avrparts(LISTID avrparts, walk_avrparts_cb cb, void *cookie);
|
||||
void sort_avrparts(LISTID avrparts);
|
||||
|
||||
int compare_memory_masked(AVRMEM * m, uint8_t buf1, uint8_t buf2);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
/* formerly pindefs.h */
|
||||
|
||||
enum {
|
||||
PPI_AVR_VCC = 1,
|
||||
PPI_AVR_BUFF,
|
||||
PIN_AVR_RESET,
|
||||
PIN_AVR_SCK,
|
||||
PIN_AVR_MOSI,
|
||||
PIN_AVR_MISO,
|
||||
PIN_LED_ERR,
|
||||
PIN_LED_RDY,
|
||||
PIN_LED_PGM,
|
||||
PIN_LED_VFY,
|
||||
N_PINS
|
||||
};
|
||||
|
||||
#define PIN_MASK (UINT_MAX>>1)
|
||||
#define PIN_INVERSE (~(PIN_MASK)) /* flag for inverted pin in serbb */
|
||||
#define PIN_MIN 0 /* smallest allowed pin number */
|
||||
#define PIN_MAX 31 /* largest allowed pin number */
|
||||
|
||||
#ifdef HAVE_LINUXGPIO
|
||||
/* Embedded systems might have a lot more gpio than only 0-31 */
|
||||
#undef PIN_MAX
|
||||
#define PIN_MAX 400 /* largest allowed pin number */
|
||||
#endif
|
||||
|
||||
/** Number of pins in each element of the bitfield */
|
||||
#define PIN_FIELD_ELEMENT_SIZE (sizeof(pinmask_t) * 8)
|
||||
/** Numer of elements to store the complete bitfield of all pins */
|
||||
#define PIN_FIELD_SIZE ((PIN_MAX + PIN_FIELD_ELEMENT_SIZE)/PIN_FIELD_ELEMENT_SIZE)
|
||||
|
||||
/**
|
||||
* This sets the corresponding bits to 1 or 0, the inverse mask is used to invert the value in necessary.
|
||||
* It uses only the lowest element (index=0) of the bitfield, which should be enough for most
|
||||
* programmers.
|
||||
*
|
||||
* @param[in] x input value
|
||||
* @param[in] pgm the programmer whose pin definitions to use
|
||||
* @param[in] pinname the logical name of the pin (PIN_AVR_*, ...)
|
||||
* @param[in] level the logical level (level != 0 => 1, level == 0 => 0),
|
||||
* if the pin is defined as inverted the resulting bit is also inverted
|
||||
* @returns the input value with the relevant bits modified
|
||||
*/
|
||||
#define SET_BITS_0(x,pgm,pinname,level) (((x) & ~(pgm)->pin[pinname].mask[0]) \
|
||||
| (\
|
||||
(pgm)->pin[pinname].mask[0] & ( \
|
||||
(level) \
|
||||
?~((pgm)->pin[pinname].inverse[0]) \
|
||||
: ((pgm)->pin[pinname].inverse[0]) \
|
||||
) \
|
||||
) \
|
||||
)
|
||||
|
||||
/**
|
||||
* Check if the corresponding bit is set (returns != 0) or cleared.
|
||||
* The inverse mask is used, to invert the relevant bits.
|
||||
* If the pin definition contains multiple pins, then a single set pin leads to return value != 0.
|
||||
* Then you have to check the relevant bits of the returned value, if you need more information.
|
||||
* It uses only the lowest element (index=0) of the bitfield, which should be enough for most
|
||||
* programmers.
|
||||
*
|
||||
* @param[in] x input value
|
||||
* @param[in] pgm the programmer whose pin definitions to use
|
||||
* @param[in] pinname the logical name of the pin (PIN_AVR_*, ...)
|
||||
* @returns the input value with only the relevant bits (which are already inverted,
|
||||
* so you get always the logical level)
|
||||
*/
|
||||
#define GET_BITS_0(x,pgm,pinname) (((x) ^ (pgm)->pin[pinname].inverse[0]) & (pgm)->pin[pinname].mask[0])
|
||||
|
||||
/**
|
||||
* Data structure to hold used pins by logical function (PIN_AVR_*, ...)
|
||||
*/
|
||||
struct pindef_t {
|
||||
pinmask_t mask[PIN_FIELD_SIZE]; ///< bitfield of used pins
|
||||
pinmask_t inverse[PIN_FIELD_SIZE]; ///< bitfield of inverse/normal usage of used pins
|
||||
};
|
||||
|
||||
/**
|
||||
* Data structure to define a checklist of valid pins for each function.
|
||||
*/
|
||||
struct pin_checklist_t {
|
||||
int pinname; ///< logical pinname eg. PIN_AVR_SCK
|
||||
int mandatory; ///< is this a mandatory pin
|
||||
const struct pindef_t* valid_pins; ///< mask defines allowed pins, inverse define is they might be used inverted
|
||||
};
|
||||
|
||||
/**
|
||||
* Adds a pin in the pin definition as normal or inverse pin.
|
||||
*
|
||||
* @param[out] pindef pin definition to update
|
||||
* @param[in] pin number of pin [0..PIN_MAX]
|
||||
* @param[in] inverse inverse (true) or normal (false) pin
|
||||
*/
|
||||
void pin_set_value(struct pindef_t * const pindef, const int pin, const bool inverse);
|
||||
|
||||
/**
|
||||
* Clear all defined pins in pindef.
|
||||
*
|
||||
* @param[out] pindef pin definition to clear
|
||||
*/
|
||||
void pin_clear_all(struct pindef_t * const pindef);
|
||||
|
||||
struct programmer_t; /* forward declaration */
|
||||
|
||||
/**
|
||||
* Convert for given programmer new pin definitions to old pin definitions.
|
||||
*
|
||||
* @param[inout] pgm programmer whose pins shall be converted.
|
||||
*/
|
||||
int pgm_fill_old_pins(struct programmer_t * const pgm);
|
||||
|
||||
/**
|
||||
* This function checks all pin of pgm against the constraints given in the checklist.
|
||||
* It checks if
|
||||
* @li any invalid pins are used
|
||||
* @li valid pins are used inverted when not allowed
|
||||
* @li any pins are used by more than one function
|
||||
* @li any mandatory pin is not set all.
|
||||
*
|
||||
* In case of any error it report the wrong function and the pin numbers.
|
||||
* For verbose >= 2 it also reports the possible correct values.
|
||||
* For verbose >=3 it shows also which pins were ok.
|
||||
*
|
||||
* @param[in] pgm the programmer to check
|
||||
* @param[in] checklist the constraint for the pins
|
||||
* @param[in] size the number of entries in checklist
|
||||
* @param[in] output false suppresses error messages to the user
|
||||
* @returns 0 if all pin definitions are valid, -1 otherwise
|
||||
*/
|
||||
int pins_check(const struct programmer_t * const pgm, const struct pin_checklist_t * const checklist, const int size, const bool output);
|
||||
|
||||
/**
|
||||
* Returns the name of the pin as string.
|
||||
*
|
||||
* @param pinname the pinname which we want as string.
|
||||
* @returns a string with the pinname, or <unknown> if pinname is invalid.
|
||||
*/
|
||||
const char * avr_pin_name(int pinname);
|
||||
|
||||
/**
|
||||
* This function returns a string representation of defined pins eg. ~1,2,~4,~5,7
|
||||
* Another execution of this function will overwrite the previous result in the static buffer.
|
||||
*
|
||||
* @param[in] pindef the pin definition for which we want the string representation
|
||||
* @returns pointer to a static string.
|
||||
*/
|
||||
const char * pins_to_str(const struct pindef_t * const pindef);
|
||||
|
||||
/**
|
||||
* This function returns a string representation of pins in the mask eg. 1,3,5-7,9,12
|
||||
* Another execution of this function will overwrite the previous result in the static buffer.
|
||||
* Consecutive pin number are representated as start-end.
|
||||
*
|
||||
* @param[in] pinmask the pin mask for which we want the string representation
|
||||
* @returns pointer to a static string.
|
||||
*/
|
||||
const char * pinmask_to_str(const pinmask_t * const pinmask);
|
||||
|
||||
/* formerly serial.h */
|
||||
|
||||
/* This is the API for the generic serial interface. The implementations are
|
||||
actually provided by the target dependant files:
|
||||
|
||||
ser_posix.c : posix serial interface.
|
||||
ser_win32.c : native win32 serial interface.
|
||||
|
||||
The target file will be selected at configure time. */
|
||||
|
||||
extern long serial_recv_timeout;
|
||||
union filedescriptor
|
||||
{
|
||||
int ifd;
|
||||
void *pfd;
|
||||
struct
|
||||
{
|
||||
void *handle;
|
||||
int rep; /* bulk read endpoint */
|
||||
int wep; /* bulk write endpoint */
|
||||
int eep; /* event read endpoint */
|
||||
int max_xfer; /* max transfer size */
|
||||
int use_interrupt_xfer; /* device uses interrupt transfers */
|
||||
} usb;
|
||||
};
|
||||
|
||||
#define SERIAL_CS5 0x0000
|
||||
#define SERIAL_CS6 0x0001
|
||||
#define SERIAL_CS7 0x0002
|
||||
#define SERIAL_CS8 0x0004
|
||||
|
||||
#define SERIAL_NO_CSTOPB 0x0000
|
||||
#define SERIAL_CSTOPB 0x0008
|
||||
|
||||
#define SERIAL_NO_CREAD 0x0000
|
||||
#define SERIAL_CREAD 0x0010
|
||||
|
||||
#define SERIAL_NO_PARITY 0x0000
|
||||
#define SERIAL_PARENB 0x0020
|
||||
#define SERIAL_PARODD 0x0040
|
||||
|
||||
#define SERIAL_NO_CLOCAL 0x0000
|
||||
#define SERIAL_CLOCAL 0x0080
|
||||
|
||||
#define SERIAL_8N1 (SERIAL_CS8 | SERIAL_NO_CSTOPB | SERIAL_CREAD | SERIAL_NO_PARITY | SERIAL_CLOCAL)
|
||||
#define SERIAL_8E1 (SERIAL_CS8 | SERIAL_NO_CSTOPB | SERIAL_CREAD | SERIAL_PARENB | SERIAL_CLOCAL)
|
||||
#define SERIAL_8E2 (SERIAL_CS8 | SERIAL_CSTOPB | SERIAL_CREAD | SERIAL_PARENB | SERIAL_CLOCAL)
|
||||
|
||||
union pinfo
|
||||
{
|
||||
struct {
|
||||
long baud;
|
||||
unsigned long cflags;
|
||||
} serialinfo;
|
||||
struct
|
||||
{
|
||||
unsigned short vid;
|
||||
unsigned short pid;
|
||||
unsigned short flags;
|
||||
#define PINFO_FL_USEHID 0x0001
|
||||
#define PINFO_FL_SILENT 0x0002 /* don't complain if not found */
|
||||
} usbinfo;
|
||||
};
|
||||
|
||||
|
||||
struct serial_device
|
||||
{
|
||||
// open should return -1 on error, other values on success
|
||||
int (*open)(char * port, union pinfo pinfo, union filedescriptor *fd);
|
||||
int (*setparams)(union filedescriptor *fd, long baud, unsigned long cflags);
|
||||
void (*close)(union filedescriptor *fd);
|
||||
|
||||
int (*send)(union filedescriptor *fd, const unsigned char * buf, size_t buflen);
|
||||
int (*recv)(union filedescriptor *fd, unsigned char * buf, size_t buflen);
|
||||
int (*drain)(union filedescriptor *fd, int display);
|
||||
|
||||
int (*set_dtr_rts)(union filedescriptor *fd, int is_on);
|
||||
|
||||
int flags;
|
||||
#define SERDEV_FL_NONE 0x0000 /* no flags */
|
||||
#define SERDEV_FL_CANSETSPEED 0x0001 /* device can change speed */
|
||||
};
|
||||
|
||||
extern struct serial_device *serdev;
|
||||
extern struct serial_device serial_serdev;
|
||||
extern struct serial_device usb_serdev;
|
||||
extern struct serial_device usb_serdev_frame;
|
||||
extern struct serial_device avrdoper_serdev;
|
||||
extern struct serial_device usbhid_serdev;
|
||||
|
||||
#define serial_open (serdev->open)
|
||||
#define serial_setparams (serdev->setparams)
|
||||
#define serial_close (serdev->close)
|
||||
#define serial_send (serdev->send)
|
||||
#define serial_recv (serdev->recv)
|
||||
#define serial_drain (serdev->drain)
|
||||
#define serial_set_dtr_rts (serdev->set_dtr_rts)
|
||||
|
||||
/* formerly pgm.h */
|
||||
|
||||
#define ON 1
|
||||
#define OFF 0
|
||||
|
||||
#define PGM_DESCLEN 80
|
||||
#define PGM_PORTLEN PATH_MAX
|
||||
#define PGM_TYPELEN 32
|
||||
#define PGM_USBSTRINGLEN 256
|
||||
|
||||
typedef enum {
|
||||
EXIT_VCC_UNSPEC,
|
||||
EXIT_VCC_ENABLED,
|
||||
EXIT_VCC_DISABLED
|
||||
} exit_vcc_t;
|
||||
|
||||
typedef enum {
|
||||
EXIT_RESET_UNSPEC,
|
||||
EXIT_RESET_ENABLED,
|
||||
EXIT_RESET_DISABLED
|
||||
} exit_reset_t;
|
||||
|
||||
typedef enum {
|
||||
EXIT_DATAHIGH_UNSPEC,
|
||||
EXIT_DATAHIGH_ENABLED,
|
||||
EXIT_DATAHIGH_DISABLED
|
||||
} exit_datahigh_t;
|
||||
|
||||
typedef enum {
|
||||
CONNTYPE_PARALLEL,
|
||||
CONNTYPE_SERIAL,
|
||||
CONNTYPE_USB
|
||||
} conntype_t;
|
||||
|
||||
typedef struct programmer_t {
|
||||
LISTID id;
|
||||
char desc[PGM_DESCLEN];
|
||||
char type[PGM_TYPELEN];
|
||||
char port[PGM_PORTLEN];
|
||||
void (*initpgm)(struct programmer_t * pgm);
|
||||
unsigned int pinno[N_PINS];
|
||||
struct pindef_t pin[N_PINS];
|
||||
exit_vcc_t exit_vcc;
|
||||
exit_reset_t exit_reset;
|
||||
exit_datahigh_t exit_datahigh;
|
||||
conntype_t conntype;
|
||||
int ppidata;
|
||||
int ppictrl;
|
||||
int baudrate;
|
||||
int usbvid;
|
||||
LISTID 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;
|
||||
int page_size; /* page size if the programmer supports paged write/load */
|
||||
int (*rdy_led) (struct programmer_t * pgm, int value);
|
||||
int (*err_led) (struct programmer_t * pgm, int value);
|
||||
int (*pgm_led) (struct programmer_t * pgm, int value);
|
||||
int (*vfy_led) (struct programmer_t * pgm, int value);
|
||||
int (*initialize) (struct programmer_t * pgm, AVRPART * p);
|
||||
void (*display) (struct programmer_t * pgm, const char * p);
|
||||
void (*enable) (struct programmer_t * pgm);
|
||||
void (*disable) (struct programmer_t * pgm);
|
||||
void (*powerup) (struct programmer_t * pgm);
|
||||
void (*powerdown) (struct programmer_t * pgm);
|
||||
int (*program_enable) (struct programmer_t * pgm, AVRPART * p);
|
||||
int (*chip_erase) (struct programmer_t * pgm, AVRPART * p);
|
||||
int (*unlock) (struct programmer_t * pgm, AVRPART * p);
|
||||
int (*cmd) (struct programmer_t * pgm, const unsigned char *cmd,
|
||||
unsigned char *res);
|
||||
int (*cmd_tpi) (struct programmer_t * pgm, const unsigned char *cmd,
|
||||
int cmd_len, unsigned char res[], int res_len);
|
||||
int (*spi) (struct programmer_t * pgm, const unsigned char *cmd,
|
||||
unsigned char *res, int count);
|
||||
int (*open) (struct programmer_t * pgm, char * port);
|
||||
void (*close) (struct programmer_t * pgm);
|
||||
int (*paged_write) (struct programmer_t * pgm, AVRPART * p, AVRMEM * m,
|
||||
unsigned int page_size, unsigned int baseaddr,
|
||||
unsigned int n_bytes);
|
||||
int (*paged_load) (struct programmer_t * pgm, AVRPART * p, AVRMEM * m,
|
||||
unsigned int page_size, unsigned int baseaddr,
|
||||
unsigned int n_bytes);
|
||||
int (*page_erase) (struct programmer_t * pgm, AVRPART * p, AVRMEM * m,
|
||||
unsigned int baseaddr);
|
||||
void (*write_setup) (struct programmer_t * pgm, AVRPART * p, AVRMEM * m);
|
||||
int (*write_byte) (struct programmer_t * pgm, AVRPART * p, AVRMEM * m,
|
||||
unsigned long addr, unsigned char value);
|
||||
int (*read_byte) (struct programmer_t * pgm, AVRPART * p, AVRMEM * m,
|
||||
unsigned long addr, unsigned char * value);
|
||||
int (*read_sig_bytes) (struct programmer_t * pgm, AVRPART * p, AVRMEM * m);
|
||||
int (*read_sib) (struct programmer_t * pgm, AVRPART * p, char *sib);
|
||||
void (*print_parms) (struct programmer_t * pgm);
|
||||
int (*set_vtarget) (struct programmer_t * pgm, double v);
|
||||
int (*set_varef) (struct programmer_t * pgm, unsigned int chan, double v);
|
||||
int (*set_fosc) (struct programmer_t * pgm, double v);
|
||||
int (*set_sck_period) (struct programmer_t * pgm, double v);
|
||||
int (*setpin) (struct programmer_t * pgm, int pinfunc, int value);
|
||||
int (*getpin) (struct programmer_t * pgm, int pinfunc);
|
||||
int (*highpulsepin) (struct programmer_t * pgm, int pinfunc);
|
||||
int (*parseexitspecs) (struct programmer_t * pgm, char *s);
|
||||
int (*perform_osccal) (struct programmer_t * pgm);
|
||||
int (*parseextparams) (struct programmer_t * pgm, LISTID xparams);
|
||||
void (*setup) (struct programmer_t * pgm);
|
||||
void (*teardown) (struct programmer_t * pgm);
|
||||
char config_file[PATH_MAX]; /* config file where defined */
|
||||
int lineno; /* config file line number */
|
||||
void *cookie; /* for private use by the programmer */
|
||||
char flag; /* for private use of the programmer */
|
||||
} PROGRAMMER;
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
PROGRAMMER * pgm_new(void);
|
||||
PROGRAMMER * pgm_dup(const PROGRAMMER * const src);
|
||||
void pgm_free(PROGRAMMER * const p);
|
||||
|
||||
void programmer_display(PROGRAMMER * pgm, const char * p);
|
||||
|
||||
/* show is a mask like this (1<<PIN_AVR_SCK)|(1<<PIN_AVR_MOSI)| ... */
|
||||
#define SHOW_ALL_PINS (~0u)
|
||||
#define SHOW_PPI_PINS ((1<<PPI_AVR_VCC)|(1<<PPI_AVR_BUFF))
|
||||
#define SHOW_AVR_PINS ((1<<PIN_AVR_RESET)|(1<<PIN_AVR_SCK)|(1<<PIN_AVR_MOSI)|(1<<PIN_AVR_MISO))
|
||||
#define SHOW_LED_PINS ((1<<PIN_LED_ERR)|(1<<PIN_LED_RDY)|(1<<PIN_LED_PGM)|(1<<PIN_LED_VFY))
|
||||
void pgm_display_generic_mask(PROGRAMMER * pgm, const char * p, unsigned int show);
|
||||
void pgm_display_generic(PROGRAMMER * pgm, const char * p);
|
||||
|
||||
PROGRAMMER * locate_programmer(LISTID programmers, const char * configid);
|
||||
|
||||
typedef void (*walk_programmers_cb)(const char *name, const char *desc,
|
||||
const char *cfgname, int cfglineno,
|
||||
void *cookie);
|
||||
void walk_programmers(LISTID programmers, walk_programmers_cb cb, void *cookie);
|
||||
|
||||
void sort_programmers(LISTID programmers);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
/* formerly avr.h */
|
||||
|
||||
typedef void (*FP_UpdateProgress)(int percent, double etime, char *hdr);
|
||||
|
||||
extern struct avrpart parts[];
|
||||
|
||||
extern FP_UpdateProgress update_progress;
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
int avr_tpi_poll_nvmbsy(PROGRAMMER *pgm);
|
||||
int avr_tpi_chip_erase(PROGRAMMER * pgm, AVRPART * p);
|
||||
int avr_tpi_program_enable(PROGRAMMER * pgm, AVRPART * p, unsigned char guard_time);
|
||||
int avr_read_byte_default(PROGRAMMER * pgm, AVRPART * p, AVRMEM * mem,
|
||||
unsigned long addr, unsigned char * value);
|
||||
|
||||
int avr_read(PROGRAMMER * pgm, AVRPART * p, char * memtype, AVRPART * v);
|
||||
|
||||
int avr_write_page(PROGRAMMER * pgm, AVRPART * p, AVRMEM * mem,
|
||||
unsigned long addr);
|
||||
|
||||
int avr_write_byte(PROGRAMMER * pgm, AVRPART * p, AVRMEM * mem,
|
||||
unsigned long addr, unsigned char data);
|
||||
|
||||
int avr_write_byte_default(PROGRAMMER * pgm, AVRPART * p, AVRMEM * mem,
|
||||
unsigned long addr, unsigned char data);
|
||||
|
||||
int avr_write(PROGRAMMER * pgm, AVRPART * p, char * memtype, int size,
|
||||
int auto_erase);
|
||||
|
||||
int avr_signature(PROGRAMMER * pgm, AVRPART * p);
|
||||
|
||||
int avr_verify(AVRPART * p, AVRPART * v, char * memtype, int size);
|
||||
|
||||
int avr_get_cycle_count(PROGRAMMER * pgm, AVRPART * p, int * cycles);
|
||||
|
||||
int avr_put_cycle_count(PROGRAMMER * pgm, AVRPART * p, int cycles);
|
||||
|
||||
int avr_mem_hiaddr(AVRMEM * mem);
|
||||
|
||||
int avr_chip_erase(PROGRAMMER * pgm, AVRPART * p);
|
||||
|
||||
int avr_unlock(PROGRAMMER * pgm, AVRPART * p);
|
||||
|
||||
void report_progress (int completed, int total, char *hdr);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
/* formerly fileio.h */
|
||||
|
||||
typedef enum {
|
||||
FMT_AUTO,
|
||||
FMT_SREC,
|
||||
FMT_IHEX,
|
||||
FMT_RBIN,
|
||||
FMT_IMM,
|
||||
FMT_HEX,
|
||||
FMT_DEC,
|
||||
FMT_OCT,
|
||||
FMT_BIN,
|
||||
FMT_ELF
|
||||
} FILEFMT;
|
||||
|
||||
struct fioparms {
|
||||
int op;
|
||||
char * mode;
|
||||
char * iodesc;
|
||||
char * dir;
|
||||
char * rw;
|
||||
unsigned int fileoffset;
|
||||
};
|
||||
|
||||
enum {
|
||||
FIO_READ,
|
||||
FIO_WRITE
|
||||
};
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
char * fmtstr(FILEFMT format);
|
||||
|
||||
int fileio(int op, char * filename, FILEFMT format,
|
||||
struct avrpart * p, char * memtype, int size);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
/* formerly safemode.h */
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* Writes the specified fuse in fusename (can be "lfuse", "hfuse", or "efuse") and verifies it. Will try up to tries
|
||||
amount of times before giving up */
|
||||
int safemode_writefuse (unsigned char fuse, char * fusename, PROGRAMMER * pgm, AVRPART * p, int tries);
|
||||
|
||||
/* Reads the fuses three times, checking that all readings are the same. This will ensure that the before values aren't in error! */
|
||||
int safemode_readfuses (unsigned char * lfuse, unsigned char * hfuse, unsigned char * efuse, unsigned char * fuse, PROGRAMMER * pgm, AVRPART * p);
|
||||
|
||||
/* This routine will store the current values pointed to by lfuse, hfuse, and efuse into an internal buffer in this routine
|
||||
when save is set to 1. When save is 0 (or not 1 really) it will copy the values from the internal buffer into the locations
|
||||
pointed to be lfuse, hfuse, and efuse. This allows you to change the fuse bits if needed from another routine (ie: have it so
|
||||
if user requests fuse bits are changed, the requested value is now verified */
|
||||
int safemode_memfuses (int save, unsigned char * lfuse, unsigned char * hfuse, unsigned char * efuse, unsigned char * fuse);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
/* formerly update.h */
|
||||
|
||||
enum {
|
||||
DEVICE_READ,
|
||||
DEVICE_WRITE,
|
||||
DEVICE_VERIFY
|
||||
};
|
||||
|
||||
enum updateflags {
|
||||
UF_NONE = 0,
|
||||
UF_NOWRITE = 1,
|
||||
UF_AUTO_ERASE = 2,
|
||||
};
|
||||
|
||||
|
||||
typedef struct update_t {
|
||||
char * memtype;
|
||||
int op;
|
||||
char * filename;
|
||||
int format;
|
||||
} UPDATE;
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
extern UPDATE * parse_op(char * s);
|
||||
extern UPDATE * dup_update(UPDATE * upd);
|
||||
extern UPDATE * new_update(int op, char * memtype, int filefmt,
|
||||
char * filename);
|
||||
extern void free_update(UPDATE * upd);
|
||||
extern int do_op(PROGRAMMER * pgm, struct avrpart * p, UPDATE * upd,
|
||||
enum updateflags flags);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
/* formerly pgm_type.h */
|
||||
|
||||
/*LISTID programmer_types;*/
|
||||
|
||||
typedef struct programmer_type_t {
|
||||
const char * const id;
|
||||
void (*initpgm)(struct programmer_t * pgm);
|
||||
const char * const desc;
|
||||
} PROGRAMMER_TYPE;
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
const PROGRAMMER_TYPE * locate_programmer_type(/*LISTID programmer_types, */const char * id);
|
||||
|
||||
typedef void (*walk_programmer_types_cb)(const char *id, const char *desc,
|
||||
void *cookie);
|
||||
void walk_programmer_types(/*LISTID programmer_types,*/ walk_programmer_types_cb cb, void *cookie);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
/* formerly config.h */
|
||||
|
||||
extern LISTID part_list;
|
||||
extern LISTID programmers;
|
||||
extern char default_programmer[];
|
||||
extern char default_parallel[];
|
||||
extern char default_serial[];
|
||||
extern double default_bitclock;
|
||||
extern int default_safemode;
|
||||
|
||||
/* This name is fixed, it's only here for symmetry with
|
||||
* default_parallel and default_serial. */
|
||||
#define DEFAULT_USB "usb"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
int init_config(void);
|
||||
|
||||
void cleanup_config(void);
|
||||
|
||||
int read_config(const char * file);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
/* formerly confwin.h */
|
||||
|
||||
#if defined(WIN32NATIVE)
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
void win_sys_config_set(char sys_config[PATH_MAX]);
|
||||
void win_usr_config_set(char usr_config[PATH_MAX]);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* WIN32NATIVE */
|
||||
|
||||
|
||||
#endif /* libavrdude_h */
|
||||
57
src/linux_ppdev.h
Normal file
57
src/linux_ppdev.h
Normal file
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
* avrdude - A Downloader/Uploader for AVR device programmers
|
||||
* Copyright (C) 2003, 2005 Theodore A. Roth
|
||||
*
|
||||
* 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/* $Id$ */
|
||||
|
||||
#ifndef linux_ppdev_h
|
||||
#define linux_ppdev_h
|
||||
|
||||
#define OBSOLETE__IOW _IOW
|
||||
|
||||
#include <sys/ioctl.h>
|
||||
#ifdef HAVE_PARPORT
|
||||
#include <linux/parport.h>
|
||||
#include <linux/ppdev.h>
|
||||
#endif
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#define ppi_claim(fd) \
|
||||
if (ioctl(fd, PPCLAIM)) { \
|
||||
avrdude_message(MSG_INFO, "%s: can't claim device \"%s\": %s\n\n", \
|
||||
progname, port, strerror(errno)); \
|
||||
close(fd); \
|
||||
return; \
|
||||
}
|
||||
|
||||
#define ppi_release(fd) \
|
||||
if (ioctl(fd, PPRELEASE)) { \
|
||||
avrdude_message(MSG_INFO, "%s: can't release device: %s\n\n", \
|
||||
progname, strerror(errno)); \
|
||||
}
|
||||
|
||||
#define DO_PPI_READ(fd, reg, valp) \
|
||||
(void)ioctl(fd, \
|
||||
(reg) == PPIDATA? PPRDATA: ((reg) == PPICTRL? PPRCONTROL: PPRSTATUS), \
|
||||
valp)
|
||||
#define DO_PPI_WRITE(fd, reg, valp) \
|
||||
(void)ioctl(fd, \
|
||||
(reg) == PPIDATA? PPWDATA: ((reg) == PPICTRL? PPWCONTROL: PPWSTATUS), \
|
||||
valp)
|
||||
|
||||
#endif /* linux_ppdev_h */
|
||||
355
src/linuxgpio.c
Normal file
355
src/linuxgpio.c
Normal file
@@ -0,0 +1,355 @@
|
||||
/*
|
||||
* avrdude - A Downloader/Uploader for AVR device programmers
|
||||
* Support for bitbanging GPIO pins using the /sys/class/gpio interface
|
||||
*
|
||||
* Copyright (C) 2013 Radoslav Kolev <radoslav@kolev.info>
|
||||
*
|
||||
* 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
|
||||
*/
|
||||
|
||||
#include "ac_cfg.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "avrdude.h"
|
||||
#include "libavrdude.h"
|
||||
|
||||
#include "bitbang.h"
|
||||
|
||||
#if HAVE_LINUXGPIO
|
||||
|
||||
/*
|
||||
* GPIO user space helpers
|
||||
*
|
||||
* Copyright 2009 Analog Devices Inc.
|
||||
* Michael Hennerich (hennerich@blackfin.uclinux.org)
|
||||
*
|
||||
* Licensed under the GPL-2 or later
|
||||
*/
|
||||
|
||||
/*
|
||||
* GPIO user space helpers
|
||||
* The following functions are acting on an "unsigned gpio" argument, which corresponds to the
|
||||
* gpio numbering scheme in the kernel (starting from 0).
|
||||
* The higher level functions use "int pin" to specify the pins with an offset of 1:
|
||||
* gpio = pin - 1;
|
||||
*/
|
||||
|
||||
#define GPIO_DIR_IN 0
|
||||
#define GPIO_DIR_OUT 1
|
||||
|
||||
static int linuxgpio_export(unsigned int gpio)
|
||||
{
|
||||
int fd, len, r;
|
||||
char buf[11];
|
||||
|
||||
fd = open("/sys/class/gpio/export", O_WRONLY);
|
||||
if (fd < 0) {
|
||||
perror("Can't open /sys/class/gpio/export");
|
||||
return fd;
|
||||
}
|
||||
|
||||
len = snprintf(buf, sizeof(buf), "%u", gpio);
|
||||
r = write(fd, buf, len);
|
||||
close(fd);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static int linuxgpio_unexport(unsigned int gpio)
|
||||
{
|
||||
int fd, len, r;
|
||||
char buf[11];
|
||||
|
||||
fd = open("/sys/class/gpio/unexport", O_WRONLY);
|
||||
if (fd < 0) {
|
||||
perror("Can't open /sys/class/gpio/unexport");
|
||||
return fd;
|
||||
}
|
||||
|
||||
len = snprintf(buf, sizeof(buf), "%u", gpio);
|
||||
r = write(fd, buf, len);
|
||||
close(fd);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static int linuxgpio_openfd(unsigned int gpio)
|
||||
{
|
||||
char filepath[60];
|
||||
|
||||
snprintf(filepath, sizeof(filepath), "/sys/class/gpio/gpio%u/value", gpio);
|
||||
return (open(filepath, O_RDWR));
|
||||
}
|
||||
|
||||
static int linuxgpio_dir(unsigned int gpio, unsigned int dir)
|
||||
{
|
||||
int fd, r;
|
||||
char buf[60];
|
||||
|
||||
snprintf(buf, sizeof(buf), "/sys/class/gpio/gpio%u/direction", gpio);
|
||||
|
||||
fd = open(buf, O_WRONLY);
|
||||
if (fd < 0) {
|
||||
perror("Can't open gpioX/direction");
|
||||
return fd;
|
||||
}
|
||||
|
||||
if (dir == GPIO_DIR_OUT)
|
||||
r = write(fd, "out", 4);
|
||||
else
|
||||
r = write(fd, "in", 3);
|
||||
|
||||
close(fd);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static int linuxgpio_dir_out(unsigned int gpio)
|
||||
{
|
||||
return linuxgpio_dir(gpio, GPIO_DIR_OUT);
|
||||
}
|
||||
|
||||
static int linuxgpio_dir_in(unsigned int gpio)
|
||||
{
|
||||
return linuxgpio_dir(gpio, GPIO_DIR_IN);
|
||||
}
|
||||
|
||||
/*
|
||||
* End of GPIO user space helpers
|
||||
*/
|
||||
|
||||
#define N_GPIO (PIN_MAX + 1)
|
||||
|
||||
/*
|
||||
* an array which holds open FDs to /sys/class/gpio/gpioXX/value for all needed pins
|
||||
*/
|
||||
static int linuxgpio_fds[N_GPIO] ;
|
||||
|
||||
|
||||
static int linuxgpio_setpin(PROGRAMMER * pgm, int pinfunc, int value)
|
||||
{
|
||||
int r;
|
||||
int pin = pgm->pinno[pinfunc]; // TODO
|
||||
|
||||
if (pin & PIN_INVERSE)
|
||||
{
|
||||
value = !value;
|
||||
pin &= PIN_MASK;
|
||||
}
|
||||
|
||||
if ( linuxgpio_fds[pin] < 0 )
|
||||
return -1;
|
||||
|
||||
if (value)
|
||||
r = write(linuxgpio_fds[pin], "1", 1);
|
||||
else
|
||||
r = write(linuxgpio_fds[pin], "0", 1);
|
||||
|
||||
if (r!=1) return -1;
|
||||
|
||||
if (pgm->ispdelay > 1)
|
||||
bitbang_delay(pgm->ispdelay);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int linuxgpio_getpin(PROGRAMMER * pgm, int pinfunc)
|
||||
{
|
||||
unsigned char invert=0;
|
||||
char c;
|
||||
int pin = pgm->pinno[pinfunc]; // TODO
|
||||
|
||||
if (pin & PIN_INVERSE)
|
||||
{
|
||||
invert = 1;
|
||||
pin &= PIN_MASK;
|
||||
}
|
||||
|
||||
if ( linuxgpio_fds[pin] < 0 )
|
||||
return -1;
|
||||
|
||||
if (lseek(linuxgpio_fds[pin], 0, SEEK_SET)<0)
|
||||
return -1;
|
||||
|
||||
if (read(linuxgpio_fds[pin], &c, 1)!=1)
|
||||
return -1;
|
||||
|
||||
if (c=='0')
|
||||
return 0+invert;
|
||||
else if (c=='1')
|
||||
return 1-invert;
|
||||
else
|
||||
return -1;
|
||||
|
||||
}
|
||||
|
||||
static int linuxgpio_highpulsepin(PROGRAMMER * pgm, int pinfunc)
|
||||
{
|
||||
int pin = pgm->pinno[pinfunc]; // TODO
|
||||
|
||||
if ( linuxgpio_fds[pin & PIN_MASK] < 0 )
|
||||
return -1;
|
||||
|
||||
linuxgpio_setpin(pgm, pinfunc, 1);
|
||||
linuxgpio_setpin(pgm, pinfunc, 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void linuxgpio_display(PROGRAMMER *pgm, const char *p)
|
||||
{
|
||||
avrdude_message(MSG_INFO, "%sPin assignment : /sys/class/gpio/gpio{n}\n",p);
|
||||
pgm_display_generic_mask(pgm, p, SHOW_AVR_PINS);
|
||||
}
|
||||
|
||||
static void linuxgpio_enable(PROGRAMMER *pgm)
|
||||
{
|
||||
/* nothing */
|
||||
}
|
||||
|
||||
static void linuxgpio_disable(PROGRAMMER *pgm)
|
||||
{
|
||||
/* nothing */
|
||||
}
|
||||
|
||||
static void linuxgpio_powerup(PROGRAMMER *pgm)
|
||||
{
|
||||
/* nothing */
|
||||
}
|
||||
|
||||
static void linuxgpio_powerdown(PROGRAMMER *pgm)
|
||||
{
|
||||
/* nothing */
|
||||
}
|
||||
|
||||
static int linuxgpio_open(PROGRAMMER *pgm, char *port)
|
||||
{
|
||||
int r, i, pin;
|
||||
|
||||
if (bitbang_check_prerequisites(pgm) < 0)
|
||||
return -1;
|
||||
|
||||
|
||||
for (i=0; i<N_GPIO; i++)
|
||||
linuxgpio_fds[i] = -1;
|
||||
//Avrdude assumes that if a pin number is 0 it means not used/available
|
||||
//this causes a problem because 0 is a valid GPIO number in Linux sysfs.
|
||||
//To avoid annoying off by one pin numbering we assume SCK, MOSI, MISO
|
||||
//and RESET pins are always defined in avrdude.conf, even as 0. If they're
|
||||
//not programming will not work anyway. The drawbacks of this approach are
|
||||
//that unwanted toggling of GPIO0 can occur and that other optional pins
|
||||
//mostry LED status, can't be set to GPIO0. It can be fixed when a better
|
||||
//solution exists.
|
||||
for (i=0; i<N_PINS; i++) {
|
||||
if ( (pgm->pinno[i] & PIN_MASK) != 0 ||
|
||||
i == PIN_AVR_RESET ||
|
||||
i == PIN_AVR_SCK ||
|
||||
i == PIN_AVR_MOSI ||
|
||||
i == PIN_AVR_MISO ) {
|
||||
pin = pgm->pinno[i] & PIN_MASK;
|
||||
if ((r=linuxgpio_export(pin)) < 0) {
|
||||
avrdude_message(MSG_INFO, "Can't export GPIO %d, already exported/busy?: %s",
|
||||
pin, strerror(errno));
|
||||
return r;
|
||||
}
|
||||
if (i == PIN_AVR_MISO)
|
||||
r=linuxgpio_dir_in(pin);
|
||||
else
|
||||
r=linuxgpio_dir_out(pin);
|
||||
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if ((linuxgpio_fds[pin]=linuxgpio_openfd(pin)) < 0)
|
||||
return linuxgpio_fds[pin];
|
||||
}
|
||||
}
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
||||
static void linuxgpio_close(PROGRAMMER *pgm)
|
||||
{
|
||||
int i, reset_pin;
|
||||
|
||||
reset_pin = pgm->pinno[PIN_AVR_RESET] & PIN_MASK;
|
||||
|
||||
//first configure all pins as input, except RESET
|
||||
//this should avoid possible conflicts when AVR firmware starts
|
||||
for (i=0; i<N_GPIO; i++) {
|
||||
if (linuxgpio_fds[i] >= 0 && i != reset_pin) {
|
||||
close(linuxgpio_fds[i]);
|
||||
linuxgpio_dir_in(i);
|
||||
linuxgpio_unexport(i);
|
||||
}
|
||||
}
|
||||
//configure RESET as input, if there's external pull up it will go high
|
||||
if (linuxgpio_fds[reset_pin] >= 0) {
|
||||
close(linuxgpio_fds[reset_pin]);
|
||||
linuxgpio_dir_in(reset_pin);
|
||||
linuxgpio_unexport(reset_pin);
|
||||
}
|
||||
}
|
||||
|
||||
void linuxgpio_initpgm(PROGRAMMER *pgm)
|
||||
{
|
||||
strcpy(pgm->type, "linuxgpio");
|
||||
|
||||
pgm_fill_old_pins(pgm); // TODO to be removed if old pin data no longer needed
|
||||
|
||||
pgm->rdy_led = bitbang_rdy_led;
|
||||
pgm->err_led = bitbang_err_led;
|
||||
pgm->pgm_led = bitbang_pgm_led;
|
||||
pgm->vfy_led = bitbang_vfy_led;
|
||||
pgm->initialize = bitbang_initialize;
|
||||
pgm->display = linuxgpio_display;
|
||||
pgm->enable = linuxgpio_enable;
|
||||
pgm->disable = linuxgpio_disable;
|
||||
pgm->powerup = linuxgpio_powerup;
|
||||
pgm->powerdown = linuxgpio_powerdown;
|
||||
pgm->program_enable = bitbang_program_enable;
|
||||
pgm->chip_erase = bitbang_chip_erase;
|
||||
pgm->cmd = bitbang_cmd;
|
||||
pgm->cmd_tpi = bitbang_cmd_tpi;
|
||||
pgm->open = linuxgpio_open;
|
||||
pgm->close = linuxgpio_close;
|
||||
pgm->setpin = linuxgpio_setpin;
|
||||
pgm->getpin = linuxgpio_getpin;
|
||||
pgm->highpulsepin = linuxgpio_highpulsepin;
|
||||
pgm->read_byte = avr_read_byte_default;
|
||||
pgm->write_byte = avr_write_byte_default;
|
||||
}
|
||||
|
||||
const char linuxgpio_desc[] = "GPIO bitbanging using the Linux sysfs interface";
|
||||
|
||||
#else /* !HAVE_LINUXGPIO */
|
||||
|
||||
void linuxgpio_initpgm(PROGRAMMER * pgm)
|
||||
{
|
||||
avrdude_message(MSG_INFO, "%s: Linux sysfs GPIO support not available in this configuration\n",
|
||||
progname);
|
||||
}
|
||||
|
||||
const char linuxgpio_desc[] = "GPIO bitbanging using the Linux sysfs interface (not available)";
|
||||
|
||||
#endif /* HAVE_LINUXGPIO */
|
||||
36
src/linuxgpio.h
Normal file
36
src/linuxgpio.h
Normal file
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* avrdude - A Downloader/Uploader for AVR device programmers
|
||||
* Copyright (C) 2013 Radoslav Kolev <radoslav@kolev.info>
|
||||
*
|
||||
* 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: par.h 722 2007-01-24 22:43:46Z joerg_wunsch $ */
|
||||
|
||||
#ifndef linuxgpio_h
|
||||
#define linuxgpio_h
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
extern const char linuxgpio_desc[];
|
||||
void linuxgpio_initpgm (PROGRAMMER * pgm);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
427
src/linuxspi.c
Normal file
427
src/linuxspi.c
Normal file
@@ -0,0 +1,427 @@
|
||||
/*
|
||||
* avrdude - A Downloader/Uploader for AVR device programmers
|
||||
* Support for using spidev userspace drivers to communicate directly over SPI
|
||||
*
|
||||
* Copyright (C) 2013 Kevin Cuzner <kevin@kevincuzner.com>
|
||||
* Copyright (C) 2018 Ralf Ramsauer <ralf@vmexit.de>
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* Support for inversion of reset pin, Tim Chilton 02/05/2014
|
||||
* Review code, rebase to latest trunk, add linux/gpio.h support, Ralf Ramsauer 2018-09-07
|
||||
*/
|
||||
|
||||
|
||||
#include "ac_cfg.h"
|
||||
|
||||
#include "avrdude.h"
|
||||
#include "libavrdude.h"
|
||||
|
||||
#include "linuxspi.h"
|
||||
|
||||
#if HAVE_LINUXSPI
|
||||
|
||||
/**
|
||||
* Linux Kernel SPI Drivers
|
||||
*
|
||||
* Copyright (C) 2006 SWAPP
|
||||
* Andrea Paterniani <a.paterniani@swapp-eng.it>
|
||||
* Copyright (C) 2007 David Brownell (simplification, cleanup)
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/spi/spidev.h>
|
||||
#include <linux/gpio.h>
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
|
||||
#define LINUXSPI "linuxspi"
|
||||
|
||||
static int fd_spidev, fd_gpiochip, fd_linehandle;
|
||||
|
||||
/**
|
||||
* @brief Sends/receives a message in full duplex mode
|
||||
* @return -1 on failure, otherwise number of bytes sent/recieved
|
||||
*/
|
||||
static int linuxspi_spi_duplex(PROGRAMMER *pgm, const unsigned char *tx, unsigned char *rx, int len)
|
||||
{
|
||||
struct spi_ioc_transfer tr;
|
||||
int ret;
|
||||
|
||||
tr = (struct spi_ioc_transfer) {
|
||||
.tx_buf = (unsigned long)tx,
|
||||
.rx_buf = (unsigned long)rx,
|
||||
.len = len,
|
||||
.delay_usecs = 1,
|
||||
.speed_hz = 1.0 / pgm->bitclock, // seconds to Hz
|
||||
.bits_per_word = 8,
|
||||
};
|
||||
|
||||
ret = ioctl(fd_spidev, SPI_IOC_MESSAGE(1), &tr);
|
||||
if (ret != len)
|
||||
avrdude_message(MSG_INFO, "\n%s: error: Unable to send SPI message\n", progname);
|
||||
|
||||
return (ret == -1) ? -1 : 0;
|
||||
}
|
||||
|
||||
static void linuxspi_setup(PROGRAMMER *pgm)
|
||||
{
|
||||
}
|
||||
|
||||
static void linuxspi_teardown(PROGRAMMER* pgm)
|
||||
{
|
||||
}
|
||||
|
||||
static int linuxspi_reset_mcu(PROGRAMMER *pgm, bool active)
|
||||
{
|
||||
struct gpiohandle_data data;
|
||||
int ret;
|
||||
|
||||
/*
|
||||
* Set the reset state and keep it. The pin will be released and set back to
|
||||
* its initial value, once the fd_gpiochip is closed.
|
||||
*/
|
||||
data.values[0] = active ^ !(pgm->pinno[PIN_AVR_RESET] & PIN_INVERSE);
|
||||
ret = ioctl(fd_linehandle, GPIOHANDLE_SET_LINE_VALUES_IOCTL, &data);
|
||||
#ifdef GPIO_V2_LINE_SET_VALUES_IOCTL
|
||||
if (ret == -1) {
|
||||
struct gpio_v2_line_values val;
|
||||
|
||||
val.mask = 1;
|
||||
val.bits = active ^ !(pgm->pinno[PIN_AVR_RESET] & PIN_INVERSE);
|
||||
|
||||
ret = ioctl(fd_linehandle, GPIO_V2_LINE_SET_VALUES_IOCTL, &val);
|
||||
}
|
||||
#endif
|
||||
if (ret == -1) {
|
||||
ret = -errno;
|
||||
avrdude_message(MSG_INFO, "%s error: Unable to set GPIO line %d value\n",
|
||||
progname, pgm->pinno[PIN_AVR_RESET] & ~PIN_INVERSE);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int linuxspi_open(PROGRAMMER *pgm, char *port)
|
||||
{
|
||||
const char *port_error =
|
||||
"%s: error: Unknown port specification. "
|
||||
"Please use the format /dev/spidev:/dev/gpiochip[:resetno]\n";
|
||||
char port_default[] = "/dev/spidev0.0:/dev/gpiochip0";
|
||||
char *spidev, *gpiochip, *reset_pin;
|
||||
struct gpiohandle_request req;
|
||||
int ret;
|
||||
|
||||
if (!strcmp(port, "unknown")) {
|
||||
port = port_default;
|
||||
}
|
||||
|
||||
spidev = strtok(port, ":");
|
||||
if (!spidev) {
|
||||
avrdude_message(MSG_INFO, port_error, progname);
|
||||
return -1;
|
||||
}
|
||||
|
||||
gpiochip = strtok(NULL, ":");
|
||||
if (!gpiochip) {
|
||||
avrdude_message(MSG_INFO, port_error, progname);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* optional: override reset pin in configuration */
|
||||
reset_pin = strtok(NULL, ":");
|
||||
if (reset_pin)
|
||||
pgm->pinno[PIN_AVR_RESET] = strtoul(reset_pin, NULL, 0);
|
||||
|
||||
strcpy(pgm->port, port);
|
||||
fd_spidev = open(pgm->port, O_RDWR);
|
||||
if (fd_spidev < 0) {
|
||||
avrdude_message(MSG_INFO, "\n%s: error: Unable to open the spidev device %s", progname, pgm->port);
|
||||
return -1;
|
||||
}
|
||||
|
||||
uint32_t mode = SPI_MODE_0 | SPI_NO_CS;
|
||||
ret = ioctl(fd_spidev, SPI_IOC_WR_MODE32, &mode);
|
||||
if (ret == -1) {
|
||||
avrdude_message(MSG_INFO, "%s: error: Unable to set SPI mode %0X on %s\n",
|
||||
progname, mode, spidev);
|
||||
goto close_spidev;
|
||||
}
|
||||
fd_gpiochip = open(gpiochip, 0);
|
||||
if (fd_gpiochip < 0) {
|
||||
avrdude_message(MSG_INFO, "\n%s error: Unable to open the gpiochip %s", progname, gpiochip);
|
||||
ret = -1;
|
||||
goto close_spidev;
|
||||
}
|
||||
|
||||
strcpy(req.consumer_label, progname);
|
||||
req.lines = 1;
|
||||
req.lineoffsets[0] = pgm->pinno[PIN_AVR_RESET] & ~PIN_INVERSE;
|
||||
req.default_values[0] = !!(pgm->pinno[PIN_AVR_RESET] & PIN_INVERSE);
|
||||
req.flags = GPIOHANDLE_REQUEST_OUTPUT;
|
||||
|
||||
ret = ioctl(fd_gpiochip, GPIO_GET_LINEHANDLE_IOCTL, &req);
|
||||
if (ret != -1)
|
||||
fd_linehandle = req.fd;
|
||||
#ifdef GPIO_V2_GET_LINE_IOCTL
|
||||
if (ret == -1) {
|
||||
struct gpio_v2_line_request reqv2;
|
||||
|
||||
memset(&reqv2, 0, sizeof(reqv2));
|
||||
reqv2.offsets[0] = pgm->pinno[PIN_AVR_RESET] & ~PIN_INVERSE;
|
||||
strncpy(reqv2.consumer, progname, sizeof(reqv2.consumer) - 1);
|
||||
reqv2.config.flags = GPIO_V2_LINE_FLAG_OUTPUT;
|
||||
reqv2.config.num_attrs = 1;
|
||||
reqv2.config.attrs[0].attr.id = GPIO_V2_LINE_ATTR_ID_OUTPUT_VALUES;
|
||||
reqv2.config.attrs[0].attr.values = !!(pgm->pinno[PIN_AVR_RESET] & PIN_INVERSE);
|
||||
reqv2.config.attrs[0].mask = 1;
|
||||
reqv2.num_lines = 1;
|
||||
|
||||
ret = ioctl(fd_gpiochip, GPIO_V2_GET_LINE_IOCTL, &reqv2);
|
||||
if (ret != -1)
|
||||
fd_linehandle = reqv2.fd;
|
||||
}
|
||||
#endif
|
||||
if (ret == -1) {
|
||||
ret = -errno;
|
||||
avrdude_message(MSG_INFO, "%s error: Unable to get GPIO line %d\n",
|
||||
progname, pgm->pinno[PIN_AVR_RESET] & ~PIN_INVERSE);
|
||||
goto close_gpiochip;
|
||||
}
|
||||
|
||||
ret = linuxspi_reset_mcu(pgm, true);
|
||||
if (ret)
|
||||
goto close_out;
|
||||
|
||||
if (pgm->baudrate != 0) {
|
||||
avrdude_message(MSG_INFO,
|
||||
"%s: obsolete use of -b <clock> option for bit clock; use -B <clock>\n",
|
||||
progname);
|
||||
pgm->bitclock = 1E6 / pgm->baudrate;
|
||||
}
|
||||
if (pgm->bitclock == 0) {
|
||||
avrdude_message(MSG_NOTICE,
|
||||
"%s: defaulting bit clock to 200 kHz\n",
|
||||
progname);
|
||||
pgm->bitclock = 5E-6; // 200 kHz - 5 µs
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
close_out:
|
||||
close(fd_linehandle);
|
||||
close_gpiochip:
|
||||
close(fd_gpiochip);
|
||||
close_spidev:
|
||||
close(fd_spidev);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void linuxspi_close(PROGRAMMER *pgm)
|
||||
{
|
||||
switch (pgm->exit_reset) {
|
||||
case EXIT_RESET_ENABLED:
|
||||
linuxspi_reset_mcu(pgm, true);
|
||||
break;
|
||||
|
||||
case EXIT_RESET_DISABLED:
|
||||
linuxspi_reset_mcu(pgm, false);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
close(fd_linehandle);
|
||||
close(fd_spidev);
|
||||
close(fd_gpiochip);
|
||||
}
|
||||
|
||||
static void linuxspi_disable(PROGRAMMER* pgm)
|
||||
{
|
||||
}
|
||||
|
||||
static void linuxspi_enable(PROGRAMMER* pgm)
|
||||
{
|
||||
}
|
||||
|
||||
static void linuxspi_display(PROGRAMMER* pgm, const char* p)
|
||||
{
|
||||
}
|
||||
|
||||
static int linuxspi_initialize(PROGRAMMER *pgm, AVRPART *p)
|
||||
{
|
||||
int tries, ret;
|
||||
|
||||
if (p->flags & AVRPART_HAS_TPI) {
|
||||
/* We do not support tpi. This is a dedicated SPI thing */
|
||||
avrdude_message(MSG_INFO, "%s: error: Programmer " LINUXSPI " does not support TPI\n", progname);
|
||||
return -1;
|
||||
}
|
||||
|
||||
//enable programming on the part
|
||||
tries = 0;
|
||||
do
|
||||
{
|
||||
ret = pgm->program_enable(pgm, p);
|
||||
if (ret == 0 || ret == -1)
|
||||
break;
|
||||
} while(tries++ < 65);
|
||||
|
||||
if (ret)
|
||||
avrdude_message(MSG_INFO, "%s: error: AVR device not responding\n", progname);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int linuxspi_cmd(PROGRAMMER *pgm, const unsigned char *cmd, unsigned char *res)
|
||||
{
|
||||
return linuxspi_spi_duplex(pgm, cmd, res, 4);
|
||||
}
|
||||
|
||||
static int linuxspi_program_enable(PROGRAMMER *pgm, AVRPART *p)
|
||||
{
|
||||
unsigned char cmd[4], res[4];
|
||||
|
||||
if (!p->op[AVR_OP_PGM_ENABLE]) {
|
||||
avrdude_message(MSG_INFO, "%s: error: program enable instruction not defined for part \"%s\"\n", progname, p->desc);
|
||||
return -1;
|
||||
}
|
||||
|
||||
memset(cmd, 0, sizeof(cmd));
|
||||
avr_set_bits(p->op[AVR_OP_PGM_ENABLE], cmd); //set the cmd
|
||||
pgm->cmd(pgm, cmd, res);
|
||||
|
||||
if (res[2] != cmd[1]) {
|
||||
/*
|
||||
* From ATtiny441 datasheet:
|
||||
*
|
||||
* In some systems, the programmer can not guarantee that SCK is held low
|
||||
* during power-up. In this case, RESET must be given a positive pulse after
|
||||
* SCK has been set to '0'. The duration of the pulse must be at least t RST
|
||||
* plus two CPU clock cycles. See Table 25-5 on page 240 for definition of
|
||||
* minimum pulse width on RESET pin, t RST
|
||||
* 2. Wait for at least 20 ms and then enable serial programming by sending
|
||||
* the Programming Enable serial instruction to the MOSI pin
|
||||
* 3. The serial programming instructions will not work if the communication
|
||||
* is out of synchronization. When in sync, the second byte (0x53) will echo
|
||||
* back when issuing the third byte of the Programming Enable instruction
|
||||
* ...
|
||||
* If the 0x53 did not echo back, give RESET a positive pulse and issue a
|
||||
* new Programming Enable command
|
||||
*/
|
||||
if (linuxspi_reset_mcu(pgm, false))
|
||||
return -1;
|
||||
usleep(5);
|
||||
if (linuxspi_reset_mcu(pgm, true))
|
||||
return -1;
|
||||
usleep(20000);
|
||||
|
||||
return -2;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int linuxspi_chip_erase(PROGRAMMER *pgm, AVRPART *p)
|
||||
{
|
||||
unsigned char cmd[4], res[4];
|
||||
|
||||
if (!p->op[AVR_OP_CHIP_ERASE]) {
|
||||
avrdude_message(MSG_INFO, "%s: error: chip erase instruction not defined for part \"%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;
|
||||
}
|
||||
|
||||
static int linuxspi_parseexitspecs(PROGRAMMER *pgm, char *s)
|
||||
{
|
||||
char *cp;
|
||||
|
||||
while ((cp = strtok(s, ","))) {
|
||||
s = 0;
|
||||
if (!strcmp(cp, "reset")) {
|
||||
pgm->exit_reset = EXIT_RESET_ENABLED;
|
||||
continue;
|
||||
}
|
||||
if (!strcmp(cp, "noreset")) {
|
||||
pgm->exit_reset = EXIT_RESET_DISABLED;
|
||||
continue;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void linuxspi_initpgm(PROGRAMMER *pgm)
|
||||
{
|
||||
strcpy(pgm->type, LINUXSPI);
|
||||
|
||||
pgm_fill_old_pins(pgm); // TODO to be removed if old pin data no longer needed
|
||||
|
||||
/* mandatory functions */
|
||||
pgm->initialize = linuxspi_initialize;
|
||||
pgm->display = linuxspi_display;
|
||||
pgm->enable = linuxspi_enable;
|
||||
pgm->disable = linuxspi_disable;
|
||||
pgm->program_enable = linuxspi_program_enable;
|
||||
pgm->chip_erase = linuxspi_chip_erase;
|
||||
pgm->cmd = linuxspi_cmd;
|
||||
pgm->open = linuxspi_open;
|
||||
pgm->close = linuxspi_close;
|
||||
pgm->read_byte = avr_read_byte_default;
|
||||
pgm->write_byte = avr_write_byte_default;
|
||||
|
||||
/* optional functions */
|
||||
pgm->setup = linuxspi_setup;
|
||||
pgm->teardown = linuxspi_teardown;
|
||||
pgm->parseexitspecs = linuxspi_parseexitspecs;
|
||||
}
|
||||
|
||||
const char linuxspi_desc[] = "SPI using Linux spidev driver";
|
||||
|
||||
#else /* !HAVE_LINUXSPI */
|
||||
|
||||
void linuxspi_initpgm(PROGRAMMER * pgm)
|
||||
{
|
||||
avrdude_message(MSG_INFO, "%s: Linux SPI driver not available in this configuration\n",
|
||||
progname);
|
||||
}
|
||||
|
||||
const char linuxspi_desc[] = "SPI using Linux spidev driver (not available)";
|
||||
|
||||
#endif /* HAVE_LINUXSPI */
|
||||
35
src/linuxspi.h
Normal file
35
src/linuxspi.h
Normal file
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* avrdude - A Downloader/Uploader for AVR device programmers
|
||||
* Copyright (C) 2013 Kevin Cuzner <kevin@kevincuner.com>
|
||||
*
|
||||
* 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
|
||||
*/
|
||||
|
||||
#ifndef linuxspi_h
|
||||
#define linuxspi_h
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
extern const char linuxspi_desc[];
|
||||
void linuxspi_initpgm (PROGRAMMER * pgm);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif //linuxspi_h
|
||||
|
||||
1407
src/lists.c
Normal file
1407
src/lists.c
Normal file
File diff suppressed because it is too large
Load Diff
1453
src/main.c
Normal file
1453
src/main.c
Normal file
File diff suppressed because it is too large
Load Diff
48
src/my_ddk_hidsdi.h
Normal file
48
src/my_ddk_hidsdi.h
Normal file
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* avrdude - A Downloader/Uploader for AVR device programmers
|
||||
* Copyright (C) 2006 Christian Starkjohann
|
||||
*
|
||||
* 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/* $Id$ */
|
||||
|
||||
/*
|
||||
The following is a replacement for hidsdi.h from the Windows DDK. It defines some
|
||||
of the types and function prototypes of this header for our project. If you
|
||||
have the Windows DDK version of this file or a version shipped with MinGW, use
|
||||
that instead.
|
||||
*/
|
||||
#ifndef MY_DDK_HIDSDI_H
|
||||
#define MY_DDK_HIDSDI_H
|
||||
#include <pshpack4.h>
|
||||
#include <ddk/hidusage.h>
|
||||
#include <ddk/hidpi.h>
|
||||
typedef struct{
|
||||
ULONG Size;
|
||||
USHORT VendorID;
|
||||
USHORT ProductID;
|
||||
USHORT VersionNumber;
|
||||
}HIDD_ATTRIBUTES;
|
||||
void __stdcall HidD_GetHidGuid(OUT LPGUID hidGuid);
|
||||
BOOLEAN __stdcall HidD_GetAttributes(IN HANDLE device, OUT HIDD_ATTRIBUTES *attributes);
|
||||
BOOLEAN __stdcall HidD_GetManufacturerString(IN HANDLE device, OUT void *buffer, IN ULONG bufferLen);
|
||||
BOOLEAN __stdcall HidD_GetProductString(IN HANDLE device, OUT void *buffer, IN ULONG bufferLen);
|
||||
BOOLEAN __stdcall HidD_GetSerialNumberString(IN HANDLE device, OUT void *buffer, IN ULONG bufferLen);
|
||||
BOOLEAN __stdcall HidD_GetFeature(IN HANDLE device, OUT void *reportBuffer, IN ULONG bufferLen);
|
||||
BOOLEAN __stdcall HidD_SetFeature(IN HANDLE device, IN void *reportBuffer, IN ULONG bufferLen);
|
||||
BOOLEAN __stdcall HidD_GetNumInputBuffers(IN HANDLE device, OUT ULONG *numBuffers);
|
||||
BOOLEAN __stdcall HidD_SetNumInputBuffers(IN HANDLE device, OUT ULONG numBuffers);
|
||||
#include <poppack.h>
|
||||
#endif /* MY_DDK_HIDSDI_H */
|
||||
411
src/par.c
Normal file
411
src/par.c
Normal file
@@ -0,0 +1,411 @@
|
||||
/*
|
||||
* avrdude - A Downloader/Uploader for AVR device programmers
|
||||
* Copyright (C) 2000-2006 Brian S. Dean <bsd@bsdhome.com>
|
||||
*
|
||||
* 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/* $Id$ */
|
||||
|
||||
#include "ac_cfg.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
|
||||
#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
|
||||
# include "freebsd_ppi.h"
|
||||
#elif defined(__linux__)
|
||||
# include "linux_ppdev.h"
|
||||
#elif defined(__sun__) || defined(__sun) /* Solaris */
|
||||
# include "solaris_ecpp.h"
|
||||
#endif
|
||||
|
||||
#include "avrdude.h"
|
||||
#include "libavrdude.h"
|
||||
|
||||
#include "ppi.h"
|
||||
#include "bitbang.h"
|
||||
#include "par.h"
|
||||
|
||||
#if HAVE_PARPORT
|
||||
|
||||
struct ppipins_t {
|
||||
int pin;
|
||||
int reg;
|
||||
int bit;
|
||||
int inverted;
|
||||
};
|
||||
|
||||
static struct ppipins_t ppipins[] = {
|
||||
{ 1, PPICTRL, 0x01, 1 },
|
||||
{ 2, PPIDATA, 0x01, 0 },
|
||||
{ 3, PPIDATA, 0x02, 0 },
|
||||
{ 4, PPIDATA, 0x04, 0 },
|
||||
{ 5, PPIDATA, 0x08, 0 },
|
||||
{ 6, PPIDATA, 0x10, 0 },
|
||||
{ 7, PPIDATA, 0x20, 0 },
|
||||
{ 8, PPIDATA, 0x40, 0 },
|
||||
{ 9, PPIDATA, 0x80, 0 },
|
||||
{ 10, PPISTATUS, 0x40, 0 },
|
||||
{ 11, PPISTATUS, 0x80, 1 },
|
||||
{ 12, PPISTATUS, 0x20, 0 },
|
||||
{ 13, PPISTATUS, 0x10, 0 },
|
||||
{ 14, PPICTRL, 0x02, 1 },
|
||||
{ 15, PPISTATUS, 0x08, 0 },
|
||||
{ 16, PPICTRL, 0x04, 0 },
|
||||
{ 17, PPICTRL, 0x08, 1 }
|
||||
};
|
||||
|
||||
#define NPINS (sizeof(ppipins)/sizeof(struct ppipins_t))
|
||||
|
||||
static int par_setpin_internal(PROGRAMMER * pgm, int pin, int value)
|
||||
{
|
||||
int inverted;
|
||||
|
||||
inverted = pin & PIN_INVERSE;
|
||||
pin &= PIN_MASK;
|
||||
|
||||
if (pin < 1 || pin > 17)
|
||||
return -1;
|
||||
|
||||
pin--;
|
||||
|
||||
if (ppipins[pin].inverted)
|
||||
inverted = !inverted;
|
||||
|
||||
if (inverted)
|
||||
value = !value;
|
||||
|
||||
if (value)
|
||||
ppi_set(&pgm->fd, ppipins[pin].reg, ppipins[pin].bit);
|
||||
else
|
||||
ppi_clr(&pgm->fd, ppipins[pin].reg, ppipins[pin].bit);
|
||||
|
||||
if (pgm->ispdelay > 1)
|
||||
bitbang_delay(pgm->ispdelay);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int par_setpin(PROGRAMMER * pgm, int pinfunc, int value)
|
||||
{
|
||||
return par_setpin_internal(pgm, pgm->pinno[pinfunc], value);
|
||||
}
|
||||
|
||||
static void par_setmany(PROGRAMMER * pgm, int pinfunc, int value)
|
||||
{
|
||||
int pin, mask;
|
||||
int pinset = pgm->pinno[pinfunc];
|
||||
|
||||
/* mask is anything non-pin - needs to be applied to each par_setpin to preserve inversion */
|
||||
mask = pinset & (~PIN_MASK);
|
||||
|
||||
for (pin = 1; pin <= 17; pin++) {
|
||||
if (pinset & (1 << pin))
|
||||
par_setpin_internal(pgm, pin | mask, value);
|
||||
}
|
||||
}
|
||||
|
||||
static int par_getpin(PROGRAMMER * pgm, int pinfunc)
|
||||
{
|
||||
int value;
|
||||
int inverted;
|
||||
int pin = pgm->pinno[pinfunc];
|
||||
|
||||
inverted = pin & PIN_INVERSE;
|
||||
pin &= PIN_MASK;
|
||||
|
||||
if (pin < 1 || pin > 17)
|
||||
return -1;
|
||||
|
||||
pin--;
|
||||
|
||||
value = ppi_get(&pgm->fd, ppipins[pin].reg, ppipins[pin].bit);
|
||||
|
||||
if (value)
|
||||
value = 1;
|
||||
|
||||
if (ppipins[pin].inverted)
|
||||
inverted = !inverted;
|
||||
|
||||
if (inverted)
|
||||
value = !value;
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
|
||||
static int par_highpulsepin(PROGRAMMER * pgm, int pinfunc)
|
||||
{
|
||||
int inverted;
|
||||
int pin = pgm->pinno[pinfunc];
|
||||
|
||||
inverted = pin & PIN_INVERSE;
|
||||
pin &= PIN_MASK;
|
||||
|
||||
if (pin < 1 || pin > 17)
|
||||
return -1;
|
||||
|
||||
pin--;
|
||||
|
||||
if (ppipins[pin].inverted)
|
||||
inverted = !inverted;
|
||||
|
||||
if (inverted) {
|
||||
ppi_clr(&pgm->fd, ppipins[pin].reg, ppipins[pin].bit);
|
||||
if (pgm->ispdelay > 1)
|
||||
bitbang_delay(pgm->ispdelay);
|
||||
|
||||
ppi_set(&pgm->fd, ppipins[pin].reg, ppipins[pin].bit);
|
||||
if (pgm->ispdelay > 1)
|
||||
bitbang_delay(pgm->ispdelay);
|
||||
} else {
|
||||
ppi_set(&pgm->fd, ppipins[pin].reg, ppipins[pin].bit);
|
||||
if (pgm->ispdelay > 1)
|
||||
bitbang_delay(pgm->ispdelay);
|
||||
|
||||
ppi_clr(&pgm->fd, ppipins[pin].reg, ppipins[pin].bit);
|
||||
if (pgm->ispdelay > 1)
|
||||
bitbang_delay(pgm->ispdelay);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* apply power to the AVR processor
|
||||
*/
|
||||
static void par_powerup(PROGRAMMER * pgm)
|
||||
{
|
||||
par_setmany(pgm, PPI_AVR_VCC, 1); /* power up */
|
||||
usleep(100000);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* remove power from the AVR processor
|
||||
*/
|
||||
static void par_powerdown(PROGRAMMER * pgm)
|
||||
{
|
||||
par_setmany(pgm, PPI_AVR_VCC, 0); /* power down */
|
||||
}
|
||||
|
||||
static void par_disable(PROGRAMMER * pgm)
|
||||
{
|
||||
par_setmany(pgm, PPI_AVR_BUFF, 1); /* turn off */
|
||||
}
|
||||
|
||||
static void par_enable(PROGRAMMER * pgm)
|
||||
{
|
||||
/*
|
||||
* Prepare to start talking to the connected device - pull reset low
|
||||
* first, delay a few milliseconds, then enable the buffer. This
|
||||
* sequence allows the AVR to be reset before the buffer is enabled
|
||||
* to avoid a short period of time where the AVR may be driving the
|
||||
* programming lines at the same time the programmer tries to. Of
|
||||
* course, if a buffer is being used, then the /RESET line from the
|
||||
* programmer needs to be directly connected to the AVR /RESET line
|
||||
* and not via the buffer chip.
|
||||
*/
|
||||
|
||||
par_setpin(pgm, PIN_AVR_RESET, 0);
|
||||
usleep(1);
|
||||
|
||||
/*
|
||||
* enable the 74367 buffer, if connected; this signal is active low
|
||||
*/
|
||||
par_setmany(pgm, PPI_AVR_BUFF, 0);
|
||||
}
|
||||
|
||||
static int par_open(PROGRAMMER * pgm, char * port)
|
||||
{
|
||||
int rc;
|
||||
|
||||
if (bitbang_check_prerequisites(pgm) < 0)
|
||||
return -1;
|
||||
|
||||
ppi_open(port, &pgm->fd);
|
||||
if (pgm->fd.ifd < 0) {
|
||||
avrdude_message(MSG_INFO, "%s: failed to open parallel port \"%s\"\n\n",
|
||||
progname, port);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* save pin values, so they can be restored when device is closed
|
||||
*/
|
||||
rc = ppi_getall(&pgm->fd, PPIDATA);
|
||||
if (rc < 0) {
|
||||
avrdude_message(MSG_INFO, "%s: error reading status of ppi data port\n", progname);
|
||||
return -1;
|
||||
}
|
||||
pgm->ppidata = rc;
|
||||
|
||||
rc = ppi_getall(&pgm->fd, PPICTRL);
|
||||
if (rc < 0) {
|
||||
avrdude_message(MSG_INFO, "%s: error reading status of ppi ctrl port\n", progname);
|
||||
return -1;
|
||||
}
|
||||
pgm->ppictrl = rc;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static void par_close(PROGRAMMER * pgm)
|
||||
{
|
||||
|
||||
/*
|
||||
* Restore pin values before closing,
|
||||
* but ensure that buffers are turned off.
|
||||
*/
|
||||
ppi_setall(&pgm->fd, PPIDATA, pgm->ppidata);
|
||||
ppi_setall(&pgm->fd, PPICTRL, pgm->ppictrl);
|
||||
|
||||
par_setmany(pgm, PPI_AVR_BUFF, 1);
|
||||
|
||||
/*
|
||||
* Handle exit specs.
|
||||
*/
|
||||
switch (pgm->exit_reset) {
|
||||
case EXIT_RESET_ENABLED:
|
||||
par_setpin(pgm, PIN_AVR_RESET, 0);
|
||||
break;
|
||||
|
||||
case EXIT_RESET_DISABLED:
|
||||
par_setpin(pgm, PIN_AVR_RESET, 1);
|
||||
break;
|
||||
|
||||
case EXIT_RESET_UNSPEC:
|
||||
/* Leave it alone. */
|
||||
break;
|
||||
}
|
||||
|
||||
switch (pgm->exit_datahigh) {
|
||||
case EXIT_DATAHIGH_ENABLED:
|
||||
ppi_setall(&pgm->fd, PPIDATA, 0xff);
|
||||
break;
|
||||
|
||||
case EXIT_DATAHIGH_DISABLED:
|
||||
ppi_setall(&pgm->fd, PPIDATA, 0x00);
|
||||
break;
|
||||
|
||||
case EXIT_DATAHIGH_UNSPEC:
|
||||
/* Leave it alone. */
|
||||
break;
|
||||
}
|
||||
|
||||
switch (pgm->exit_vcc) {
|
||||
case EXIT_VCC_ENABLED:
|
||||
par_setmany(pgm, PPI_AVR_VCC, 1);
|
||||
break;
|
||||
|
||||
case EXIT_VCC_DISABLED:
|
||||
par_setmany(pgm, PPI_AVR_VCC, 0);
|
||||
break;
|
||||
|
||||
case EXIT_VCC_UNSPEC:
|
||||
/* Leave it alone. */
|
||||
break;
|
||||
}
|
||||
|
||||
ppi_close(&pgm->fd);
|
||||
pgm->fd.ifd = -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* parse the -E string
|
||||
*/
|
||||
static int par_parseexitspecs(PROGRAMMER * pgm, char *s)
|
||||
{
|
||||
char *cp;
|
||||
|
||||
while ((cp = strtok(s, ","))) {
|
||||
if (strcmp(cp, "reset") == 0) {
|
||||
pgm->exit_reset = EXIT_RESET_ENABLED;
|
||||
}
|
||||
else if (strcmp(cp, "noreset") == 0) {
|
||||
pgm->exit_reset = EXIT_RESET_DISABLED;
|
||||
}
|
||||
else if (strcmp(cp, "vcc") == 0) {
|
||||
pgm->exit_vcc = EXIT_VCC_ENABLED;
|
||||
}
|
||||
else if (strcmp(cp, "novcc") == 0) {
|
||||
pgm->exit_vcc = EXIT_VCC_DISABLED;
|
||||
}
|
||||
else if (strcmp(cp, "d_high") == 0) {
|
||||
pgm->exit_datahigh = EXIT_DATAHIGH_ENABLED;
|
||||
}
|
||||
else if (strcmp(cp, "d_low") == 0) {
|
||||
pgm->exit_datahigh = EXIT_DATAHIGH_DISABLED;
|
||||
}
|
||||
else {
|
||||
return -1;
|
||||
}
|
||||
s = 0; /* strtok() should be called with the actual string only once */
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void par_initpgm(PROGRAMMER * pgm)
|
||||
{
|
||||
strcpy(pgm->type, "PPI");
|
||||
|
||||
pgm_fill_old_pins(pgm); // TODO to be removed if old pin data no longer needed
|
||||
|
||||
pgm->exit_vcc = EXIT_VCC_UNSPEC;
|
||||
pgm->exit_reset = EXIT_RESET_UNSPEC;
|
||||
pgm->exit_datahigh = EXIT_DATAHIGH_UNSPEC;
|
||||
|
||||
pgm->rdy_led = bitbang_rdy_led;
|
||||
pgm->err_led = bitbang_err_led;
|
||||
pgm->pgm_led = bitbang_pgm_led;
|
||||
pgm->vfy_led = bitbang_vfy_led;
|
||||
pgm->initialize = bitbang_initialize;
|
||||
pgm->display = pgm_display_generic;
|
||||
pgm->enable = par_enable;
|
||||
pgm->disable = par_disable;
|
||||
pgm->powerup = par_powerup;
|
||||
pgm->powerdown = par_powerdown;
|
||||
pgm->program_enable = bitbang_program_enable;
|
||||
pgm->chip_erase = bitbang_chip_erase;
|
||||
pgm->cmd = bitbang_cmd;
|
||||
pgm->cmd_tpi = bitbang_cmd_tpi;
|
||||
pgm->spi = bitbang_spi;
|
||||
pgm->open = par_open;
|
||||
pgm->close = par_close;
|
||||
pgm->setpin = par_setpin;
|
||||
pgm->getpin = par_getpin;
|
||||
pgm->highpulsepin = par_highpulsepin;
|
||||
pgm->parseexitspecs = par_parseexitspecs;
|
||||
pgm->read_byte = avr_read_byte_default;
|
||||
pgm->write_byte = avr_write_byte_default;
|
||||
}
|
||||
|
||||
#else /* !HAVE_PARPORT */
|
||||
|
||||
void par_initpgm(PROGRAMMER * pgm)
|
||||
{
|
||||
avrdude_message(MSG_INFO, "%s: parallel port access not available in this configuration\n",
|
||||
progname);
|
||||
}
|
||||
|
||||
#endif /* HAVE_PARPORT */
|
||||
|
||||
const char par_desc[] = "Parallel port bitbanging";
|
||||
35
src/par.h
Normal file
35
src/par.h
Normal file
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* avrdude - A Downloader/Uploader for AVR device programmers
|
||||
* Copyright (C) 2000-2004 Brian S. Dean <bsd@bsdhome.com>
|
||||
*
|
||||
* 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/* $Id$ */
|
||||
|
||||
#ifndef par_h
|
||||
#define par_h
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
extern const char par_desc[];
|
||||
void par_initpgm (PROGRAMMER * pgm);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
332
src/pgm.c
Normal file
332
src/pgm.c
Normal file
@@ -0,0 +1,332 @@
|
||||
/*
|
||||
* avrdude - A Downloader/Uploader for AVR device programmers
|
||||
* Copyright (C) 2002-2004 Brian S. Dean <bsd@bsdhome.com>
|
||||
* Copyright 2007 Joerg Wunsch <j@uriah.heep.sax.de>
|
||||
*
|
||||
* 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/* $Id$ */
|
||||
|
||||
#include "ac_cfg.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "avrdude.h"
|
||||
#include "libavrdude.h"
|
||||
|
||||
static int pgm_default_2 (struct programmer_t *, AVRPART *);
|
||||
static int pgm_default_3 (struct programmer_t * pgm, AVRPART * p, AVRMEM * mem,
|
||||
unsigned long addr, unsigned char * value);
|
||||
static void pgm_default_4 (struct programmer_t *);
|
||||
static int pgm_default_5 (struct programmer_t * pgm, AVRPART * p, AVRMEM * mem,
|
||||
unsigned long addr, unsigned char data);
|
||||
static void pgm_default_6 (struct programmer_t *, const char *);
|
||||
|
||||
|
||||
static int pgm_default_open (struct programmer_t *pgm, char * name)
|
||||
{
|
||||
avrdude_message(MSG_INFO, "\n%s: Fatal error: Programmer does not support open()",
|
||||
progname);
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int pgm_default_led (struct programmer_t * pgm, int value)
|
||||
{
|
||||
/*
|
||||
* If programmer has no LEDs, just do nothing.
|
||||
*/
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static void pgm_default_powerup_powerdown (struct programmer_t * pgm)
|
||||
{
|
||||
/*
|
||||
* If programmer does not support powerup/down, just do nothing.
|
||||
*/
|
||||
}
|
||||
|
||||
|
||||
PROGRAMMER * pgm_new(void)
|
||||
{
|
||||
int i;
|
||||
PROGRAMMER * pgm;
|
||||
|
||||
pgm = (PROGRAMMER *)malloc(sizeof(*pgm));
|
||||
if (pgm == NULL) {
|
||||
avrdude_message(MSG_INFO, "%s: out of memory allocating programmer structure\n",
|
||||
progname);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memset(pgm, 0, sizeof(*pgm));
|
||||
|
||||
pgm->id = lcreat(NULL, 0);
|
||||
pgm->usbpid = lcreat(NULL, 0);
|
||||
pgm->desc[0] = 0;
|
||||
pgm->type[0] = 0;
|
||||
pgm->config_file[0] = 0;
|
||||
pgm->lineno = 0;
|
||||
pgm->baudrate = 0;
|
||||
pgm->initpgm = NULL;
|
||||
|
||||
for (i=0; i<N_PINS; i++) {
|
||||
pgm->pinno[i] = 0;
|
||||
pin_clear_all(&(pgm->pin[i]));
|
||||
}
|
||||
|
||||
/*
|
||||
* mandatory functions - these are called without checking to see
|
||||
* whether they are assigned or not
|
||||
*/
|
||||
pgm->initialize = pgm_default_2;
|
||||
pgm->display = pgm_default_6;
|
||||
pgm->enable = pgm_default_4;
|
||||
pgm->disable = pgm_default_4;
|
||||
pgm->powerup = pgm_default_powerup_powerdown;
|
||||
pgm->powerdown = pgm_default_powerup_powerdown;
|
||||
pgm->program_enable = pgm_default_2;
|
||||
pgm->chip_erase = pgm_default_2;
|
||||
pgm->open = pgm_default_open;
|
||||
pgm->close = pgm_default_4;
|
||||
pgm->read_byte = pgm_default_3;
|
||||
pgm->write_byte = pgm_default_5;
|
||||
|
||||
/*
|
||||
* predefined functions - these functions have a valid default
|
||||
* implementation. Hence, they don't need to be defined in
|
||||
* the programmer.
|
||||
*/
|
||||
pgm->rdy_led = pgm_default_led;
|
||||
pgm->err_led = pgm_default_led;
|
||||
pgm->pgm_led = pgm_default_led;
|
||||
pgm->vfy_led = pgm_default_led;
|
||||
|
||||
/*
|
||||
* optional functions - these are checked to make sure they are
|
||||
* assigned before they are called
|
||||
*/
|
||||
pgm->cmd = NULL;
|
||||
pgm->cmd_tpi = NULL;
|
||||
pgm->spi = NULL;
|
||||
pgm->paged_write = NULL;
|
||||
pgm->paged_load = NULL;
|
||||
pgm->write_setup = NULL;
|
||||
pgm->read_sig_bytes = NULL;
|
||||
pgm->set_vtarget = NULL;
|
||||
pgm->set_varef = NULL;
|
||||
pgm->set_fosc = NULL;
|
||||
pgm->perform_osccal = NULL;
|
||||
pgm->parseextparams = NULL;
|
||||
pgm->setup = NULL;
|
||||
pgm->teardown = NULL;
|
||||
|
||||
return pgm;
|
||||
}
|
||||
|
||||
void pgm_free(PROGRAMMER * const p)
|
||||
{
|
||||
ldestroy_cb(p->id, free);
|
||||
ldestroy_cb(p->usbpid, free);
|
||||
p->id = NULL;
|
||||
p->usbpid = NULL;
|
||||
/* this is done by pgm_teardown, but usually cookie is not set to NULL */
|
||||
/* if (p->cookie !=NULL) {
|
||||
free(p->cookie);
|
||||
p->cookie = NULL;
|
||||
}*/
|
||||
free(p);
|
||||
}
|
||||
|
||||
PROGRAMMER * pgm_dup(const PROGRAMMER * const src)
|
||||
{
|
||||
PROGRAMMER * pgm;
|
||||
LNODEID ln;
|
||||
|
||||
pgm = (PROGRAMMER *)malloc(sizeof(*pgm));
|
||||
if (pgm == NULL) {
|
||||
avrdude_message(MSG_INFO, "%s: out of memory allocating programmer structure\n",
|
||||
progname);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memcpy(pgm, src, sizeof(*pgm));
|
||||
|
||||
pgm->id = lcreat(NULL, 0);
|
||||
pgm->usbpid = lcreat(NULL, 0);
|
||||
|
||||
for (ln = lfirst(src->usbpid); ln; ln = lnext(ln)) {
|
||||
int *ip = malloc(sizeof(int));
|
||||
if (ip == NULL) {
|
||||
avrdude_message(MSG_INFO, "%s: out of memory allocating programmer structure\n",
|
||||
progname);
|
||||
exit(1);
|
||||
}
|
||||
*ip = *(int *) ldata(ln);
|
||||
ladd(pgm->usbpid, ip);
|
||||
}
|
||||
|
||||
return pgm;
|
||||
}
|
||||
|
||||
|
||||
static void pgm_default(void)
|
||||
{
|
||||
avrdude_message(MSG_INFO, "%s: programmer operation not supported\n", progname);
|
||||
}
|
||||
|
||||
|
||||
static int pgm_default_2 (struct programmer_t * pgm, AVRPART * p)
|
||||
{
|
||||
pgm_default();
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int pgm_default_3 (struct programmer_t * pgm, AVRPART * p, AVRMEM * mem,
|
||||
unsigned long addr, unsigned char * value)
|
||||
{
|
||||
pgm_default();
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void pgm_default_4 (struct programmer_t * pgm)
|
||||
{
|
||||
pgm_default();
|
||||
}
|
||||
|
||||
static int pgm_default_5 (struct programmer_t * pgm, AVRPART * p, AVRMEM * mem,
|
||||
unsigned long addr, unsigned char data)
|
||||
{
|
||||
pgm_default();
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void pgm_default_6 (struct programmer_t * pgm, const char * p)
|
||||
{
|
||||
pgm_default();
|
||||
}
|
||||
|
||||
|
||||
void programmer_display(PROGRAMMER * pgm, const char * p)
|
||||
{
|
||||
avrdude_message(MSG_INFO, "%sProgrammer Type : %s\n", p, pgm->type);
|
||||
avrdude_message(MSG_INFO, "%sDescription : %s\n", p, pgm->desc);
|
||||
|
||||
pgm->display(pgm, p);
|
||||
}
|
||||
|
||||
|
||||
void pgm_display_generic_mask(PROGRAMMER * pgm, const char * p, unsigned int show)
|
||||
{
|
||||
if(show & (1<<PPI_AVR_VCC))
|
||||
avrdude_message(MSG_INFO, "%s VCC = %s\n", p, pins_to_str(&pgm->pin[PPI_AVR_VCC]));
|
||||
if(show & (1<<PPI_AVR_BUFF))
|
||||
avrdude_message(MSG_INFO, "%s BUFF = %s\n", p, pins_to_str(&pgm->pin[PPI_AVR_BUFF]));
|
||||
if(show & (1<<PIN_AVR_RESET))
|
||||
avrdude_message(MSG_INFO, "%s RESET = %s\n", p, pins_to_str(&pgm->pin[PIN_AVR_RESET]));
|
||||
if(show & (1<<PIN_AVR_SCK))
|
||||
avrdude_message(MSG_INFO, "%s SCK = %s\n", p, pins_to_str(&pgm->pin[PIN_AVR_SCK]));
|
||||
if(show & (1<<PIN_AVR_MOSI))
|
||||
avrdude_message(MSG_INFO, "%s MOSI = %s\n", p, pins_to_str(&pgm->pin[PIN_AVR_MOSI]));
|
||||
if(show & (1<<PIN_AVR_MISO))
|
||||
avrdude_message(MSG_INFO, "%s MISO = %s\n", p, pins_to_str(&pgm->pin[PIN_AVR_MISO]));
|
||||
if(show & (1<<PIN_LED_ERR))
|
||||
avrdude_message(MSG_INFO, "%s ERR LED = %s\n", p, pins_to_str(&pgm->pin[PIN_LED_ERR]));
|
||||
if(show & (1<<PIN_LED_RDY))
|
||||
avrdude_message(MSG_INFO, "%s RDY LED = %s\n", p, pins_to_str(&pgm->pin[PIN_LED_RDY]));
|
||||
if(show & (1<<PIN_LED_PGM))
|
||||
avrdude_message(MSG_INFO, "%s PGM LED = %s\n", p, pins_to_str(&pgm->pin[PIN_LED_PGM]));
|
||||
if(show & (1<<PIN_LED_VFY))
|
||||
avrdude_message(MSG_INFO, "%s VFY LED = %s\n", p, pins_to_str(&pgm->pin[PIN_LED_VFY]));
|
||||
}
|
||||
|
||||
void pgm_display_generic(PROGRAMMER * pgm, const char * p)
|
||||
{
|
||||
pgm_display_generic_mask(pgm, p, SHOW_ALL_PINS);
|
||||
}
|
||||
|
||||
PROGRAMMER * locate_programmer(LISTID programmers, const char * configid)
|
||||
{
|
||||
LNODEID ln1, ln2;
|
||||
PROGRAMMER * p = NULL;
|
||||
const char * id;
|
||||
int found;
|
||||
|
||||
found = 0;
|
||||
|
||||
for (ln1=lfirst(programmers); ln1 && !found; ln1=lnext(ln1)) {
|
||||
p = ldata(ln1);
|
||||
for (ln2=lfirst(p->id); ln2 && !found; ln2=lnext(ln2)) {
|
||||
id = ldata(ln2);
|
||||
if (strcasecmp(configid, id) == 0)
|
||||
found = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (found)
|
||||
return p;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Iterate over the list of programmers given as "programmers", and
|
||||
* call the callback function cb for each entry found. cb is being
|
||||
* passed the following arguments:
|
||||
* . the name of the programmer (for -c)
|
||||
* . the descriptive text given in the config file
|
||||
* . the name of the config file this programmer has been defined in
|
||||
* . the line number of the config file this programmer has been defined at
|
||||
* . the "cookie" passed into walk_programmers() (opaque client data)
|
||||
*/
|
||||
void walk_programmers(LISTID programmers, walk_programmers_cb cb, void *cookie)
|
||||
{
|
||||
LNODEID ln1;
|
||||
LNODEID ln2;
|
||||
PROGRAMMER * p;
|
||||
|
||||
for (ln1 = lfirst(programmers); ln1; ln1 = lnext(ln1)) {
|
||||
p = ldata(ln1);
|
||||
for (ln2=lfirst(p->id); ln2; ln2=lnext(ln2)) {
|
||||
cb(ldata(ln2), p->desc, p->config_file, p->lineno, cookie);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Compare function to sort the list of programmers
|
||||
*/
|
||||
static int sort_programmer_compare(PROGRAMMER * p1,PROGRAMMER * p2)
|
||||
{
|
||||
char* id1;
|
||||
char* id2;
|
||||
if(p1 == NULL || p2 == NULL) {
|
||||
return 0;
|
||||
}
|
||||
id1 = ldata(lfirst(p1->id));
|
||||
id2 = ldata(lfirst(p2->id));
|
||||
return strncasecmp(id1,id2,AVR_IDLEN);
|
||||
}
|
||||
|
||||
/*
|
||||
* Sort the list of programmers given as "programmers"
|
||||
*/
|
||||
void sort_programmers(LISTID programmers)
|
||||
{
|
||||
lsort(programmers,(int (*)(void*, void*)) sort_programmer_compare);
|
||||
}
|
||||
|
||||
160
src/pgm_type.c
Normal file
160
src/pgm_type.c
Normal file
@@ -0,0 +1,160 @@
|
||||
/*
|
||||
* avrdude - A Downloader/Uploader for AVR device programmers
|
||||
* Copyright (C) 2002-2004 Brian S. Dean <bsd@bsdhome.com>
|
||||
* Copyright 2007 Joerg Wunsch <j@uriah.heep.sax.de>
|
||||
*
|
||||
* 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/* $Id: pgm.c 976 2011-08-23 21:03:36Z joerg_wunsch $ */
|
||||
|
||||
#include "ac_cfg.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "avrdude.h"
|
||||
#include "libavrdude.h"
|
||||
|
||||
#include "arduino.h"
|
||||
#include "avr910.h"
|
||||
#include "avrftdi.h"
|
||||
#include "buspirate.h"
|
||||
#include "butterfly.h"
|
||||
#include "flip1.h"
|
||||
#include "flip2.h"
|
||||
#include "ft245r.h"
|
||||
#include "jtagmkI.h"
|
||||
#include "jtagmkII.h"
|
||||
#include "jtag3.h"
|
||||
#include "linuxgpio.h"
|
||||
#include "linuxspi.h"
|
||||
#include "par.h"
|
||||
#include "pickit2.h"
|
||||
#include "ppi.h"
|
||||
#include "serbb.h"
|
||||
#include "serialupdi.h"
|
||||
#include "stk500.h"
|
||||
#include "stk500generic.h"
|
||||
#include "stk500v2.h"
|
||||
#include "usbasp.h"
|
||||
#include "usbtiny.h"
|
||||
#include "wiring.h"
|
||||
#include "xbee.h"
|
||||
|
||||
|
||||
const PROGRAMMER_TYPE programmers_types[] = {
|
||||
{"arduino", arduino_initpgm, arduino_desc},
|
||||
{"avr910", avr910_initpgm, avr910_desc},
|
||||
{"avrftdi", avrftdi_initpgm, avrftdi_desc},
|
||||
{"buspirate", buspirate_initpgm, buspirate_desc},
|
||||
{"buspirate_bb", buspirate_bb_initpgm, buspirate_bb_desc},
|
||||
{"butterfly", butterfly_initpgm, butterfly_desc},
|
||||
{"butterfly_mk", butterfly_mk_initpgm, butterfly_mk_desc},
|
||||
{"dragon_dw", jtagmkII_dragon_dw_initpgm, jtagmkII_dragon_dw_desc},
|
||||
{"dragon_hvsp", stk500v2_dragon_hvsp_initpgm, stk500v2_dragon_hvsp_desc},
|
||||
{"dragon_isp", stk500v2_dragon_isp_initpgm, stk500v2_dragon_isp_desc},
|
||||
{"dragon_jtag", jtagmkII_dragon_initpgm, jtagmkII_dragon_desc},
|
||||
{"dragon_pdi", jtagmkII_dragon_pdi_initpgm, jtagmkII_dragon_pdi_desc},
|
||||
{"dragon_pp", stk500v2_dragon_pp_initpgm, stk500v2_dragon_pp_desc},
|
||||
{"flip1", flip1_initpgm, flip1_desc},
|
||||
{"flip2", flip2_initpgm, flip2_desc},
|
||||
{"ftdi_syncbb", ft245r_initpgm, ft245r_desc},
|
||||
{"jtagmki", jtagmkI_initpgm, jtagmkI_desc},
|
||||
{"jtagmkii", jtagmkII_initpgm, jtagmkII_desc},
|
||||
{"jtagmkii_avr32", jtagmkII_avr32_initpgm, jtagmkII_avr32_desc},
|
||||
{"jtagmkii_dw", jtagmkII_dw_initpgm, jtagmkII_dw_desc},
|
||||
{"jtagmkii_isp", stk500v2_jtagmkII_initpgm, stk500v2_jtagmkII_desc},
|
||||
{"jtagmkii_pdi", jtagmkII_pdi_initpgm, jtagmkII_pdi_desc},
|
||||
{"jtagice3", jtag3_initpgm, jtag3_desc},
|
||||
{"jtagice3_pdi", jtag3_pdi_initpgm, jtag3_pdi_desc},
|
||||
{"jtagice3_updi", jtag3_updi_initpgm, jtag3_updi_desc},
|
||||
{"jtagice3_dw", jtag3_dw_initpgm, jtag3_dw_desc},
|
||||
{"jtagice3_isp", stk500v2_jtag3_initpgm, stk500v2_jtag3_desc},
|
||||
{"linuxgpio", linuxgpio_initpgm, linuxgpio_desc},
|
||||
{"linuxspi", linuxspi_initpgm, linuxspi_desc},
|
||||
{"par", par_initpgm, par_desc},
|
||||
{"pickit2", pickit2_initpgm, pickit2_desc},
|
||||
{"serbb", serbb_initpgm, serbb_desc},
|
||||
{"serialupdi", serialupdi_initpgm, serialupdi_desc},
|
||||
{"stk500", stk500_initpgm, stk500_desc},
|
||||
{"stk500generic", stk500generic_initpgm, stk500generic_desc},
|
||||
{"stk500v2", stk500v2_initpgm, stk500v2_desc},
|
||||
{"stk500hvsp", stk500hvsp_initpgm, stk500hvsp_desc},
|
||||
{"stk500pp", stk500pp_initpgm, stk500pp_desc},
|
||||
{"stk600", stk600_initpgm, stk600_desc},
|
||||
{"stk600hvsp", stk600hvsp_initpgm, stk600hvsp_desc},
|
||||
{"stk600pp", stk600pp_initpgm, stk600pp_desc},
|
||||
{"usbasp", usbasp_initpgm, usbasp_desc},
|
||||
{"usbtiny", usbtiny_initpgm, usbtiny_desc},
|
||||
{"wiring", wiring_initpgm, wiring_desc},
|
||||
{"xbee", xbee_initpgm, xbee_desc},
|
||||
};
|
||||
|
||||
const PROGRAMMER_TYPE * locate_programmer_type(const char * id)
|
||||
{
|
||||
const PROGRAMMER_TYPE * p = NULL;
|
||||
int i;
|
||||
int found;
|
||||
|
||||
found = 0;
|
||||
|
||||
for (i = 0; i < sizeof(programmers_types)/sizeof(programmers_types[0]) && !found; i++) {
|
||||
p = &(programmers_types[i]);
|
||||
if (strcasecmp(id, p->id) == 0)
|
||||
found = 1;
|
||||
}
|
||||
|
||||
if (found)
|
||||
return p;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Iterate over the list of programmers given as "programmers", and
|
||||
* call the callback function cb for each entry found. cb is being
|
||||
* passed the following arguments:
|
||||
* . the name of the programmer (for -c)
|
||||
* . the descriptive text given in the config file
|
||||
* . the name of the config file this programmer has been defined in
|
||||
* . the line number of the config file this programmer has been defined at
|
||||
* . the "cookie" passed into walk_programmers() (opaque client data)
|
||||
*/
|
||||
/*
|
||||
void walk_programmer_types(LISTID programmer_types, walk_programmer_types_cb cb, void *cookie)
|
||||
{
|
||||
LNODEID ln1;
|
||||
PROGRAMMER * p;
|
||||
|
||||
for (ln1 = lfirst(programmers); ln1; ln1 = lnext(ln1)) {
|
||||
p = ldata(ln1);
|
||||
cb(p->id, p->desc, cookie);
|
||||
}
|
||||
}
|
||||
}*/
|
||||
|
||||
void walk_programmer_types(walk_programmer_types_cb cb, void *cookie)
|
||||
{
|
||||
const PROGRAMMER_TYPE * p;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < sizeof(programmers_types)/sizeof(programmers_types[0]); i++) {
|
||||
p = &(programmers_types[i]);
|
||||
cb(p->id, p->desc, cookie);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
1342
src/pickit2.c
Normal file
1342
src/pickit2.c
Normal file
File diff suppressed because it is too large
Load Diff
35
src/pickit2.h
Normal file
35
src/pickit2.h
Normal file
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* avrdude - A Downloader/Uploader for AVR device programmers
|
||||
* Copyright (C) 2006 Thomas Fischl
|
||||
*
|
||||
* 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/* $Id: pickit2.h 2010-05-03 dbrown $ */
|
||||
|
||||
#ifndef pickit2_h
|
||||
#define pickit2_h
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
extern const char pickit2_desc[];
|
||||
void pickit2_initpgm (PROGRAMMER * pgm);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // pickit2_h
|
||||
370
src/pindefs.c
Normal file
370
src/pindefs.c
Normal file
@@ -0,0 +1,370 @@
|
||||
/*
|
||||
* avrdude - A Downloader/Uploader for AVR device programmers
|
||||
* Copyright (C) 2000-2004 Brian S. Dean <bsd@bsdhome.com>
|
||||
*
|
||||
* 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/* $Id: pindefs.h 1132 2013-01-09 19:23:30Z rliebscher $ */
|
||||
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "avrdude.h"
|
||||
#include "libavrdude.h"
|
||||
|
||||
/**
|
||||
* Adds a pin in the pin definition as normal or inverse pin.
|
||||
*
|
||||
* @param[out] pindef pin definition to update
|
||||
* @param[in] pin number of pin [0..PIN_MAX]
|
||||
* @param[in] inverse inverse (true) or normal (false) pin
|
||||
*/
|
||||
void pin_set_value(struct pindef_t * const pindef, const int pin, const bool inverse) {
|
||||
|
||||
pindef->mask[pin / PIN_FIELD_ELEMENT_SIZE] |= 1 << (pin % PIN_FIELD_ELEMENT_SIZE);
|
||||
if(inverse) {
|
||||
pindef->inverse[pin / PIN_FIELD_ELEMENT_SIZE] |= (1 << (pin % PIN_FIELD_ELEMENT_SIZE));
|
||||
} else {
|
||||
pindef->inverse[pin / PIN_FIELD_ELEMENT_SIZE] &= ~(1 << (pin % PIN_FIELD_ELEMENT_SIZE));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear all defined pins in pindef.
|
||||
*
|
||||
* @param[out] pindef pin definition to clear
|
||||
*/
|
||||
void pin_clear_all(struct pindef_t * const pindef) {
|
||||
memset(pindef, 0, sizeof(struct pindef_t));
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert new pin definition to old pin number
|
||||
*
|
||||
* @param[in] pindef new pin definition structure
|
||||
* @param[out] pinno old pin definition integer
|
||||
*/
|
||||
static int pin_fill_old_pinno(const struct pindef_t * const pindef, unsigned int * const pinno) {
|
||||
bool found = false;
|
||||
int i;
|
||||
for(i = 0; i < PIN_MAX; i++) {
|
||||
if(pindef->mask[i / PIN_FIELD_ELEMENT_SIZE] & (1 << (i % PIN_FIELD_ELEMENT_SIZE))) {
|
||||
if(found) {
|
||||
avrdude_message(MSG_INFO, "Multiple pins found\n"); //TODO
|
||||
return -1;
|
||||
}
|
||||
found = true;
|
||||
*pinno = i;
|
||||
if(pindef->inverse[i / PIN_FIELD_ELEMENT_SIZE] & (1 << (i % PIN_FIELD_ELEMENT_SIZE))) {
|
||||
*pinno |= PIN_INVERSE;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert new pin definition to old pinlist, does not support mixed inverted/non-inverted pin
|
||||
*
|
||||
* @param[in] pindef new pin definition structure
|
||||
* @param[out] pinno old pin definition integer
|
||||
*/
|
||||
static int pin_fill_old_pinlist(const struct pindef_t * const pindef, unsigned int * const pinno) {
|
||||
int i;
|
||||
|
||||
for(i = 0; i < PIN_FIELD_SIZE; i++) {
|
||||
if(i == 0) {
|
||||
if((pindef->mask[i] & ~PIN_MASK) != 0) {
|
||||
avrdude_message(MSG_INFO, "Pins of higher index than max field size for old pinno found\n");
|
||||
return -1;
|
||||
}
|
||||
if (pindef->mask[i] == 0) {
|
||||
/* this pin function is not using any pins */
|
||||
*pinno = 0;
|
||||
} else if(pindef->mask[i] == pindef->inverse[i]) { /* all set bits in mask are set in inverse */
|
||||
*pinno = pindef->mask[i];
|
||||
*pinno |= PIN_INVERSE;
|
||||
} else if(pindef->mask[i] == ((~pindef->inverse[i]) & pindef->mask[i])) { /* all set bits in mask are cleared in inverse */
|
||||
*pinno = pindef->mask[i];
|
||||
} else {
|
||||
avrdude_message(MSG_INFO, "pins have different polarity set\n");
|
||||
return -1;
|
||||
}
|
||||
} else if(pindef->mask[i] != 0) {
|
||||
avrdude_message(MSG_INFO, "Pins have higher number than fit in old format\n");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Convert for given programmer new pin definitions to old pin definitions.
|
||||
*
|
||||
* @param[inout] pgm programmer whose pins shall be converted.
|
||||
*/
|
||||
int pgm_fill_old_pins(struct programmer_t * const pgm) {
|
||||
|
||||
if (pin_fill_old_pinlist(&(pgm->pin[PPI_AVR_VCC]), &(pgm->pinno[PPI_AVR_VCC])) < 0)
|
||||
return -1;
|
||||
if (pin_fill_old_pinlist(&(pgm->pin[PPI_AVR_BUFF]), &(pgm->pinno[PPI_AVR_BUFF])) < 0)
|
||||
return -1;
|
||||
if (pin_fill_old_pinno(&(pgm->pin[PIN_AVR_RESET]), &(pgm->pinno[PIN_AVR_RESET])) < 0)
|
||||
return -1;
|
||||
if (pin_fill_old_pinno(&(pgm->pin[PIN_AVR_SCK]), &(pgm->pinno[PIN_AVR_SCK])) < 0)
|
||||
return -1;
|
||||
if (pin_fill_old_pinno(&(pgm->pin[PIN_AVR_MOSI]), &(pgm->pinno[PIN_AVR_MOSI])) < 0)
|
||||
return -1;
|
||||
if (pin_fill_old_pinno(&(pgm->pin[PIN_AVR_MISO]), &(pgm->pinno[PIN_AVR_MISO])) < 0)
|
||||
return -1;
|
||||
if (pin_fill_old_pinno(&(pgm->pin[PIN_LED_ERR]), &(pgm->pinno[PIN_LED_ERR])) < 0)
|
||||
return -1;
|
||||
if (pin_fill_old_pinno(&(pgm->pin[PIN_LED_RDY]), &(pgm->pinno[PIN_LED_RDY])) < 0)
|
||||
return -1;
|
||||
if (pin_fill_old_pinno(&(pgm->pin[PIN_LED_PGM]), &(pgm->pinno[PIN_LED_PGM])) < 0)
|
||||
return -1;
|
||||
if (pin_fill_old_pinno(&(pgm->pin[PIN_LED_VFY]), &(pgm->pinno[PIN_LED_VFY])) < 0)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function returns a string representation of pins in the mask eg. 1,3,5-7,9,12
|
||||
* Another execution of this function will overwrite the previous result in the static buffer.
|
||||
* Consecutive pin number are representated as start-end.
|
||||
*
|
||||
* @param[in] pinmask the pin mask for which we want the string representation
|
||||
* @returns pointer to a static string.
|
||||
*/
|
||||
const char * pinmask_to_str(const pinmask_t * const pinmask) {
|
||||
static char buf[(PIN_MAX + 1) * 5]; // should be enough for PIN_MAX=255
|
||||
char *p = buf;
|
||||
int n;
|
||||
int pin;
|
||||
const char * fmt;
|
||||
int start = -1;
|
||||
int end = -1;
|
||||
|
||||
buf[0] = 0;
|
||||
for(pin = PIN_MIN; pin <= PIN_MAX; pin++) {
|
||||
int index = pin / PIN_FIELD_ELEMENT_SIZE;
|
||||
int bit = pin % PIN_FIELD_ELEMENT_SIZE;
|
||||
if(pinmask[index] & (1 << bit)) {
|
||||
bool output = false;
|
||||
if(start == -1) {
|
||||
output = true;
|
||||
start = pin;
|
||||
end = start;
|
||||
} else if(pin == end + 1) {
|
||||
end = pin;
|
||||
} else {
|
||||
if(start != end) {
|
||||
n = sprintf(p, "-%d", end);
|
||||
p += n;
|
||||
}
|
||||
output = true;
|
||||
start = pin;
|
||||
end = start;
|
||||
}
|
||||
if(output) {
|
||||
fmt = (buf[0] == 0) ? "%d" : ",%d";
|
||||
n = sprintf(p, fmt, pin);
|
||||
p += n;
|
||||
}
|
||||
}
|
||||
}
|
||||
if(start != end) {
|
||||
n = sprintf(p, "-%d", end);
|
||||
p += n;
|
||||
}
|
||||
|
||||
if(buf[0] == 0)
|
||||
return "(no pins)";
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This function checks all pin of pgm against the constraints given in the checklist.
|
||||
* It checks if
|
||||
* @li any invalid pins are used
|
||||
* @li valid pins are used inverted when not allowed
|
||||
* @li any pins are used by more than one function
|
||||
* @li any mandatory pin is not set all.
|
||||
*
|
||||
* In case of any error it report the wrong function and the pin numbers.
|
||||
* For verbose >= 2 it also reports the possible correct values.
|
||||
* For verbose >=3 it shows also which pins were ok.
|
||||
*
|
||||
* @param[in] pgm the programmer to check
|
||||
* @param[in] checklist the constraint for the pins
|
||||
* @param[in] size the number of entries in checklist
|
||||
* @returns 0 if all pin definitions are valid, -1 otherwise
|
||||
*/
|
||||
int pins_check(const struct programmer_t * const pgm, const struct pin_checklist_t * const checklist, const int size, bool output) {
|
||||
static const struct pindef_t no_valid_pins = {{0}, {0}}; // default value if check list does not contain anything else
|
||||
int rv = 0; // return value
|
||||
int pinname; // loop counter through pinnames
|
||||
pinmask_t already_used_all[PIN_FIELD_SIZE] = {0}; // collect pin definitions of all pin names for check of double use
|
||||
// loop over all possible pinnames
|
||||
for(pinname = 0; pinname < N_PINS; pinname++) {
|
||||
bool used = false;
|
||||
bool invalid = false;
|
||||
bool inverse = false;
|
||||
int index;
|
||||
int segment;
|
||||
bool mandatory_used = false;
|
||||
pinmask_t invalid_used[PIN_FIELD_SIZE] = {0};
|
||||
pinmask_t inverse_used[PIN_FIELD_SIZE] = {0};
|
||||
pinmask_t already_used[PIN_FIELD_SIZE] = {0};
|
||||
const struct pindef_t * valid_pins = &no_valid_pins;
|
||||
bool is_mandatory = false;
|
||||
bool is_ok = true;
|
||||
//find corresponding check pattern
|
||||
for(index = 0; index < size; index++) {
|
||||
if(checklist[index].pinname == pinname) {
|
||||
valid_pins = checklist[index].valid_pins;
|
||||
is_mandatory = checklist[index].mandatory;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
for(segment = 0; segment < PIN_FIELD_SIZE; segment++) {
|
||||
// check if for mandatory any pin is defined
|
||||
invalid_used[segment] = pgm->pin[pinname].mask[segment] & ~valid_pins->mask[segment];
|
||||
if(is_mandatory && (0 != (pgm->pin[pinname].mask[segment] & valid_pins->mask[segment]))) {
|
||||
mandatory_used = true;
|
||||
}
|
||||
// check if it does not use any non valid pins
|
||||
invalid_used[segment] = pgm->pin[pinname].mask[segment] & ~valid_pins->mask[segment];
|
||||
if(invalid_used[segment]) {
|
||||
invalid = true;
|
||||
}
|
||||
// check if it does not use any valid pins as inverse if not allowed
|
||||
inverse_used[segment] = pgm->pin[pinname].inverse[segment] & valid_pins->mask[segment] & ~valid_pins->inverse[segment];
|
||||
if(inverse_used[segment]) {
|
||||
inverse = true;
|
||||
}
|
||||
// check if it does not use same pins as other function
|
||||
already_used[segment] = pgm->pin[pinname].mask[segment] & already_used_all[segment];
|
||||
if(already_used[segment]) {
|
||||
used = true;
|
||||
}
|
||||
already_used_all[segment] |= pgm->pin[pinname].mask[segment];
|
||||
}
|
||||
if(invalid) {
|
||||
if(output) {
|
||||
avrdude_message(MSG_INFO, "%s: %s: Following pins are not valid pins for this function: %s\n",
|
||||
progname, avr_pin_name(pinname), pinmask_to_str(invalid_used));
|
||||
avrdude_message(MSG_NOTICE2, "%s: %s: Valid pins for this function are: %s\n",
|
||||
progname, avr_pin_name(pinname), pinmask_to_str(valid_pins->mask));
|
||||
}
|
||||
is_ok = false;
|
||||
}
|
||||
if(inverse) {
|
||||
if(output) {
|
||||
avrdude_message(MSG_INFO, "%s: %s: Following pins are not usable as inverse pins for this function: %s\n",
|
||||
progname, avr_pin_name(pinname), pinmask_to_str(inverse_used));
|
||||
avrdude_message(MSG_NOTICE2, "%s: %s: Valid inverse pins for this function are: %s\n",
|
||||
progname, avr_pin_name(pinname), pinmask_to_str(valid_pins->inverse));
|
||||
}
|
||||
is_ok = false;
|
||||
}
|
||||
if(used) {
|
||||
if(output) {
|
||||
avrdude_message(MSG_INFO, "%s: %s: Following pins are set for other functions too: %s\n",
|
||||
progname, avr_pin_name(pinname), pinmask_to_str(already_used));
|
||||
is_ok = false;
|
||||
}
|
||||
}
|
||||
if(!mandatory_used && is_mandatory && !invalid) {
|
||||
if(output) {
|
||||
avrdude_message(MSG_INFO, "%s: %s: Mandatory pin is not defined.\n",
|
||||
progname, avr_pin_name(pinname));
|
||||
}
|
||||
is_ok = false;
|
||||
}
|
||||
if(!is_ok) {
|
||||
rv = -1;
|
||||
} else if(output) {
|
||||
avrdude_message(MSG_DEBUG, "%s: %s: Pin is ok.\n",
|
||||
progname, avr_pin_name(pinname));
|
||||
}
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function returns a string representation of defined pins eg. ~1,2,~4,~5,7
|
||||
* Another execution of this function will overwrite the previous result in the static buffer.
|
||||
*
|
||||
* @param[in] pindef the pin definition for which we want the string representation
|
||||
* @returns pointer to a static string.
|
||||
*/
|
||||
const char * pins_to_str(const struct pindef_t * const pindef) {
|
||||
static char buf[(PIN_MAX + 1) * 5]; // should be enough for PIN_MAX=255
|
||||
char *p = buf;
|
||||
int n;
|
||||
int pin;
|
||||
const char * fmt;
|
||||
|
||||
buf[0] = 0;
|
||||
for(pin = PIN_MIN; pin <= PIN_MAX; pin++) {
|
||||
int index = pin / PIN_FIELD_ELEMENT_SIZE;
|
||||
int bit = pin % PIN_FIELD_ELEMENT_SIZE;
|
||||
if(pindef->mask[index] & (1 << bit)) {
|
||||
if(pindef->inverse[index] & (1 << bit)) {
|
||||
fmt = (buf[0] == 0) ? "~%d" : ",~%d";
|
||||
} else {
|
||||
fmt = (buf[0] == 0) ? " %d" : ",%d";
|
||||
}
|
||||
n = sprintf(p, fmt, pin);
|
||||
p += n;
|
||||
}
|
||||
}
|
||||
|
||||
if(buf[0] == 0)
|
||||
return " (not used)";
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the name of the pin as string.
|
||||
*
|
||||
* @param pinname the pinname which we want as string.
|
||||
* @returns a string with the pinname, or <unknown> if pinname is invalid.
|
||||
*/
|
||||
const char * avr_pin_name(int pinname) {
|
||||
switch(pinname) {
|
||||
case PPI_AVR_VCC : return "VCC";
|
||||
case PPI_AVR_BUFF : return "BUFF";
|
||||
case PIN_AVR_RESET : return "RESET";
|
||||
case PIN_AVR_SCK : return "SCK";
|
||||
case PIN_AVR_MOSI : return "MOSI";
|
||||
case PIN_AVR_MISO : return "MISO";
|
||||
case PIN_LED_ERR : return "ERRLED";
|
||||
case PIN_LED_RDY : return "RDYLED";
|
||||
case PIN_LED_PGM : return "PGMLED";
|
||||
case PIN_LED_VFY : return "VFYLED";
|
||||
default : return "<unknown>";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
236
src/ppi.c
Normal file
236
src/ppi.c
Normal file
@@ -0,0 +1,236 @@
|
||||
/*
|
||||
* avrdude - A Downloader/Uploader for AVR device programmers
|
||||
* Copyright (C) 2000-2004 Brian S. Dean <bsd@bsdhome.com>
|
||||
*
|
||||
* 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/* $Id$ */
|
||||
|
||||
|
||||
#if !defined(WIN32NATIVE)
|
||||
|
||||
#include "ac_cfg.h"
|
||||
|
||||
#if HAVE_PARPORT
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
|
||||
#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
|
||||
# include "freebsd_ppi.h"
|
||||
#elif defined(__linux__)
|
||||
# include "linux_ppdev.h"
|
||||
#elif defined(__sun__) || defined(__sun) /* Solaris */
|
||||
# include "solaris_ecpp.h"
|
||||
#endif
|
||||
|
||||
#include "avrdude.h"
|
||||
#include "libavrdude.h"
|
||||
|
||||
#include "ppi.h"
|
||||
|
||||
enum {
|
||||
PPI_READ,
|
||||
PPI_WRITE,
|
||||
PPI_SHADOWREAD
|
||||
};
|
||||
|
||||
static int ppi_shadow_access(union filedescriptor *fdp, int reg,
|
||||
unsigned char *v, unsigned char action)
|
||||
{
|
||||
static unsigned char shadow[3];
|
||||
int shadow_num;
|
||||
|
||||
switch (reg) {
|
||||
case PPIDATA:
|
||||
shadow_num = 0;
|
||||
break;
|
||||
case PPICTRL:
|
||||
shadow_num = 1;
|
||||
break;
|
||||
case PPISTATUS:
|
||||
shadow_num = 2;
|
||||
break;
|
||||
default:
|
||||
avrdude_message(MSG_INFO, "%s: avr_set(): invalid register=%d\n",
|
||||
progname, reg);
|
||||
return -1;
|
||||
break;
|
||||
}
|
||||
|
||||
switch (action) {
|
||||
case PPI_SHADOWREAD:
|
||||
*v = shadow[shadow_num];
|
||||
break;
|
||||
case PPI_READ:
|
||||
DO_PPI_READ(fdp->ifd, reg, v);
|
||||
shadow[shadow_num]=*v;
|
||||
break;
|
||||
case PPI_WRITE:
|
||||
shadow[shadow_num]=*v;
|
||||
DO_PPI_WRITE(fdp->ifd, reg, v);
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* set the indicated bit of the specified register.
|
||||
*/
|
||||
int ppi_set(union filedescriptor *fdp, int reg, int bit)
|
||||
{
|
||||
unsigned char v;
|
||||
int rc;
|
||||
|
||||
rc = ppi_shadow_access(fdp, reg, &v, PPI_SHADOWREAD);
|
||||
v |= bit;
|
||||
rc |= ppi_shadow_access(fdp, reg, &v, PPI_WRITE);
|
||||
|
||||
if (rc)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* clear the indicated bit of the specified register.
|
||||
*/
|
||||
int ppi_clr(union filedescriptor *fdp, int reg, int bit)
|
||||
{
|
||||
unsigned char v;
|
||||
int rc;
|
||||
|
||||
rc = ppi_shadow_access(fdp, reg, &v, PPI_SHADOWREAD);
|
||||
v &= ~bit;
|
||||
rc |= ppi_shadow_access(fdp, reg, &v, PPI_WRITE);
|
||||
|
||||
if (rc)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* get the indicated bit of the specified register.
|
||||
*/
|
||||
int ppi_get(union filedescriptor *fdp, int reg, int bit)
|
||||
{
|
||||
unsigned char v;
|
||||
int rc;
|
||||
|
||||
rc = ppi_shadow_access(fdp, reg, &v, PPI_READ);
|
||||
v &= bit;
|
||||
|
||||
if (rc)
|
||||
return -1;
|
||||
|
||||
return v; /* v == bit */
|
||||
}
|
||||
|
||||
/*
|
||||
* toggle the indicated bit of the specified register.
|
||||
*/
|
||||
int ppi_toggle(union filedescriptor *fdp, int reg, int bit)
|
||||
{
|
||||
unsigned char v;
|
||||
int rc;
|
||||
|
||||
rc = ppi_shadow_access(fdp, reg, &v, PPI_SHADOWREAD);
|
||||
v ^= bit;
|
||||
rc |= ppi_shadow_access(fdp, reg, &v, PPI_WRITE);
|
||||
|
||||
if (rc)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* get all bits of the specified register.
|
||||
*/
|
||||
int ppi_getall(union filedescriptor *fdp, int reg)
|
||||
{
|
||||
unsigned char v;
|
||||
int rc;
|
||||
|
||||
rc = ppi_shadow_access(fdp, reg, &v, PPI_READ);
|
||||
|
||||
if (rc)
|
||||
return -1;
|
||||
|
||||
return v; /* v == bit */
|
||||
}
|
||||
|
||||
/*
|
||||
* set all bits of the specified register to val.
|
||||
*/
|
||||
int ppi_setall(union filedescriptor *fdp, int reg, int val)
|
||||
{
|
||||
unsigned char v;
|
||||
int rc;
|
||||
|
||||
v = val;
|
||||
rc = ppi_shadow_access(fdp, reg, &v, PPI_WRITE);
|
||||
|
||||
if (rc)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void ppi_open(char * port, union filedescriptor *fdp)
|
||||
{
|
||||
int fd;
|
||||
unsigned char v;
|
||||
|
||||
fd = open(port, O_RDWR);
|
||||
if (fd < 0) {
|
||||
avrdude_message(MSG_INFO, "%s: can't open device \"%s\": %s\n",
|
||||
progname, port, strerror(errno));
|
||||
fdp->ifd = -1;
|
||||
return;
|
||||
}
|
||||
|
||||
ppi_claim (fd);
|
||||
|
||||
/*
|
||||
* Initialize shadow registers
|
||||
*/
|
||||
|
||||
ppi_shadow_access (fdp, PPIDATA, &v, PPI_READ);
|
||||
ppi_shadow_access (fdp, PPICTRL, &v, PPI_READ);
|
||||
ppi_shadow_access (fdp, PPISTATUS, &v, PPI_READ);
|
||||
|
||||
fdp->ifd = fd;
|
||||
}
|
||||
|
||||
|
||||
void ppi_close(union filedescriptor *fdp)
|
||||
{
|
||||
ppi_release (fdp->ifd);
|
||||
close(fdp->ifd);
|
||||
}
|
||||
|
||||
#endif /* HAVE_PARPORT */
|
||||
|
||||
#endif /* !WIN32NATIVE */
|
||||
59
src/ppi.h
Normal file
59
src/ppi.h
Normal file
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
* avrdude - A Downloader/Uploader for AVR device programmers
|
||||
* Copyright (C) 2000-2004 Brian S. Dean <bsd@bsdhome.com>
|
||||
*
|
||||
* 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/* $Id$ */
|
||||
|
||||
#ifndef ppi_h
|
||||
#define ppi_h
|
||||
|
||||
/*
|
||||
* PPI registers
|
||||
*/
|
||||
enum {
|
||||
PPIDATA,
|
||||
PPICTRL,
|
||||
PPISTATUS
|
||||
};
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
int ppi_get (union filedescriptor *fdp, int reg, int bit);
|
||||
|
||||
int ppi_set (union filedescriptor *fdp, int reg, int bit);
|
||||
|
||||
int ppi_clr (union filedescriptor *fdp, int reg, int bit);
|
||||
|
||||
int ppi_getall (union filedescriptor *fdp, int reg);
|
||||
|
||||
int ppi_setall (union filedescriptor *fdp, int reg, int val);
|
||||
|
||||
int ppi_toggle (union filedescriptor *fdp, int reg, int bit);
|
||||
|
||||
void ppi_open (char * port, union filedescriptor *fdp);
|
||||
|
||||
void ppi_close (union filedescriptor *fdp);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
417
src/ppiwin.c
Normal file
417
src/ppiwin.c
Normal file
@@ -0,0 +1,417 @@
|
||||
/*
|
||||
* avrdude - A Downloader/Uploader for AVR device programmers
|
||||
* Copyright (C) 2003, 2004, 2006
|
||||
* Eric B. Weddington <eweddington@cso.atmel.com>
|
||||
* Copyright 2008, Joerg Wunsch
|
||||
*
|
||||
* 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/* $Id$ */
|
||||
|
||||
/*
|
||||
This is the parallel port interface for Windows built using Cygwin.
|
||||
|
||||
In the ppi_* functions that access the parallel port registers,
|
||||
fd = parallel port address
|
||||
reg = register as defined in an enum in ppi.h. This must be converted
|
||||
to a proper offset of the base address.
|
||||
*/
|
||||
|
||||
|
||||
#include "ac_cfg.h"
|
||||
|
||||
#if defined (WIN32NATIVE)
|
||||
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <windows.h>
|
||||
#include <sys/time.h>
|
||||
#include <windows.h>
|
||||
|
||||
#include "avrdude.h"
|
||||
#include "libavrdude.h"
|
||||
|
||||
#include "ppi.h"
|
||||
|
||||
#define DEVICE_LPT1 "lpt1"
|
||||
#define DEVICE_LPT2 "lpt2"
|
||||
#define DEVICE_LPT3 "lpt3"
|
||||
|
||||
#define DEVICE_MAX 3
|
||||
|
||||
typedef struct
|
||||
{
|
||||
const char *name;
|
||||
int base_address;
|
||||
} winpp;
|
||||
|
||||
static const winpp winports[DEVICE_MAX] =
|
||||
{
|
||||
{DEVICE_LPT1, 0x378},
|
||||
{DEVICE_LPT2, 0x278},
|
||||
{DEVICE_LPT3, 0x3BC},
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/* FUNCTION PROTOTYPES */
|
||||
static int winnt_pp_open(void);
|
||||
static unsigned short port_get(union filedescriptor *fdp, int reg);
|
||||
static unsigned char reg2offset(int reg);
|
||||
static unsigned char inb(unsigned short port);
|
||||
static void outb(unsigned char value, unsigned short port);
|
||||
|
||||
|
||||
|
||||
/* FUNCTION DEFINITIONS */
|
||||
|
||||
void ppi_open(char *port, union filedescriptor *fdp)
|
||||
{
|
||||
unsigned char i;
|
||||
int fd;
|
||||
|
||||
fd = winnt_pp_open();
|
||||
|
||||
if(fd < 0)
|
||||
{
|
||||
avrdude_message(MSG_INFO, "%s: can't open device \"giveio\"\n\n", progname);
|
||||
fdp->ifd = -1;
|
||||
return;
|
||||
}
|
||||
|
||||
/* Search the windows port names for a match */
|
||||
fd = -1;
|
||||
for(i = 0; i < DEVICE_MAX; i++)
|
||||
{
|
||||
if(strcmp(winports[i].name, port) == 0)
|
||||
{
|
||||
/* Set the file descriptor with the Windows parallel port base address. */
|
||||
fd = winports[i].base_address;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(fd == -1)
|
||||
{
|
||||
/*
|
||||
* Supplied port name did not match any of the pre-defined
|
||||
* names. Try interpreting it as a numeric
|
||||
* (hexadecimal/decimal/octal) address.
|
||||
*/
|
||||
char *cp;
|
||||
|
||||
fd = strtol(port, &cp, 0);
|
||||
if(*port == '\0' || *cp != '\0')
|
||||
{
|
||||
avrdude_message(MSG_INFO, "%s: port name \"%s\" is neither lpt1/2/3 nor valid number\n",
|
||||
progname, port);
|
||||
fd = -1;
|
||||
}
|
||||
}
|
||||
if(fd < 0)
|
||||
{
|
||||
avrdude_message(MSG_INFO, "%s: can't open device \"%s\"\n\n", progname, port);
|
||||
fdp->ifd = -1;
|
||||
return;
|
||||
}
|
||||
|
||||
fdp->ifd = fd;
|
||||
}
|
||||
|
||||
|
||||
#define DRIVERNAME "\\\\.\\giveio"
|
||||
static int winnt_pp_open(void)
|
||||
{
|
||||
// Only try to use giveio under Windows NT/2000/XP.
|
||||
OSVERSIONINFO ver_info;
|
||||
|
||||
memset(&ver_info, 0, sizeof(ver_info));
|
||||
|
||||
ver_info.dwOSVersionInfoSize = sizeof(ver_info);
|
||||
|
||||
if(!GetVersionEx(&ver_info))
|
||||
{
|
||||
return(-1);
|
||||
}
|
||||
else if(ver_info.dwPlatformId == VER_PLATFORM_WIN32_NT)
|
||||
{
|
||||
HANDLE h = CreateFile(DRIVERNAME,
|
||||
GENERIC_READ,
|
||||
0,
|
||||
NULL,
|
||||
OPEN_EXISTING,
|
||||
FILE_ATTRIBUTE_NORMAL,
|
||||
NULL);
|
||||
|
||||
if(h == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
return(-1);
|
||||
}
|
||||
|
||||
/* Close immediately. The process now has the rights it needs. */
|
||||
if(h != NULL)
|
||||
{
|
||||
CloseHandle(h);
|
||||
}
|
||||
}
|
||||
return(0);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void ppi_close(union filedescriptor *fdp)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* set the indicated bit of the specified register.
|
||||
*/
|
||||
int ppi_set(union filedescriptor *fdp, int reg, int bit)
|
||||
{
|
||||
unsigned char v;
|
||||
unsigned short port;
|
||||
|
||||
port = port_get(fdp, reg);
|
||||
v = inb(port);
|
||||
v |= bit;
|
||||
outb(v, port);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* clear the indicated bit of the specified register.
|
||||
*/
|
||||
int ppi_clr(union filedescriptor *fdp, int reg, int bit)
|
||||
{
|
||||
unsigned char v;
|
||||
unsigned short port;
|
||||
|
||||
port = port_get(fdp, reg);
|
||||
v = inb(port);
|
||||
v &= ~bit;
|
||||
outb(v, port);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* get the indicated bit of the specified register.
|
||||
*/
|
||||
int ppi_get(union filedescriptor *fdp, int reg, int bit)
|
||||
{
|
||||
unsigned char v;
|
||||
|
||||
v = inb(port_get(fdp, reg));
|
||||
v &= bit;
|
||||
|
||||
return(v);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* toggle the indicated bit of the specified register.
|
||||
*/
|
||||
int ppi_toggle(union filedescriptor *fdp, int reg, int bit)
|
||||
{
|
||||
unsigned char v;
|
||||
unsigned short port;
|
||||
|
||||
port = port_get(fdp, reg);
|
||||
|
||||
v = inb(port);
|
||||
v ^= bit;
|
||||
outb(v, port);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* get all bits of the specified register.
|
||||
*/
|
||||
int ppi_getall(union filedescriptor *fdp, int reg)
|
||||
{
|
||||
unsigned char v;
|
||||
|
||||
v = inb(port_get(fdp, reg));
|
||||
|
||||
return((int)v);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* set all bits of the specified register to val.
|
||||
*/
|
||||
int ppi_setall(union filedescriptor *fdp, int reg, int val)
|
||||
{
|
||||
outb((unsigned char)val, port_get(fdp, reg));
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/* Calculate port address to access. */
|
||||
static unsigned short port_get(union filedescriptor *fdp, int reg)
|
||||
{
|
||||
return((unsigned short)(fdp->ifd + reg2offset(reg)));
|
||||
}
|
||||
|
||||
|
||||
/* Convert register enum to offset of base address. */
|
||||
static unsigned char reg2offset(int reg)
|
||||
{
|
||||
unsigned char offset = 0;
|
||||
|
||||
switch(reg)
|
||||
{
|
||||
case PPIDATA:
|
||||
{
|
||||
offset = 0;
|
||||
break;
|
||||
}
|
||||
case PPISTATUS:
|
||||
{
|
||||
offset = 1;
|
||||
break;
|
||||
}
|
||||
case PPICTRL:
|
||||
{
|
||||
offset = 2;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return(offset);
|
||||
}
|
||||
|
||||
|
||||
/* Read in value from port. */
|
||||
static unsigned char inb(unsigned short port)
|
||||
{
|
||||
unsigned char t;
|
||||
|
||||
asm volatile ("in %1, %0"
|
||||
: "=a" (t)
|
||||
: "d" (port));
|
||||
|
||||
return t;
|
||||
}
|
||||
|
||||
|
||||
/* Write value to port. */
|
||||
static void outb(unsigned char value, unsigned short port)
|
||||
{
|
||||
asm volatile ("out %1, %0"
|
||||
:
|
||||
: "d" (port), "a" (value) );
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
#if !defined(HAVE_GETTIMEOFDAY)
|
||||
struct timezone;
|
||||
int gettimeofday(struct timeval *tv, struct timezone *unused){
|
||||
// i've found only ms resolution, avrdude expects us
|
||||
|
||||
SYSTEMTIME st;
|
||||
GetSystemTime(&st);
|
||||
|
||||
tv->tv_sec=(long)(st.wSecond+st.wMinute*60+st.wHour*3600);
|
||||
tv->tv_usec=(long)(st.wMilliseconds*1000);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif /* HAVE_GETTIMEOFDAY */
|
||||
|
||||
// #define W32USLEEPDBG
|
||||
|
||||
#ifdef W32USLEEPDBG
|
||||
|
||||
# define DEBUG_QueryPerformanceCounter(arg) QueryPerformanceCounter(arg)
|
||||
# define DEBUG_DisplayTimingInfo(start, stop, freq, us, has_highperf) \
|
||||
do { \
|
||||
unsigned long dt; \
|
||||
dt = (unsigned long)((stop.QuadPart - start.QuadPart) * 1000 * 1000 \
|
||||
/ freq.QuadPart); \
|
||||
avrdude_message(MSG_INFO, \
|
||||
"hpt:%i usleep usec:%lu sleep msec:%lu timed usec:%lu\n", \
|
||||
has_highperf, us, ((us + 999) / 1000), dt); \
|
||||
} while (0)
|
||||
|
||||
#else
|
||||
|
||||
# define DEBUG_QueryPerformanceCounter(arg)
|
||||
# define DEBUG_DisplayTimingInfo(start, stop, freq, us, has_highperf)
|
||||
|
||||
#endif
|
||||
|
||||
#if !defined(HAVE_USLEEP)
|
||||
int usleep(unsigned int us)
|
||||
{
|
||||
int has_highperf;
|
||||
LARGE_INTEGER freq,start,stop,loopend;
|
||||
|
||||
// workaround: although usleep is very precise if using
|
||||
// high-performance-timers there are sometimes problems with
|
||||
// verify - increasing the delay helps sometimes but not
|
||||
// realiably. There must be some other problem. Maybe just
|
||||
// with my test-hardware maybe in the code-base.
|
||||
//// us=(unsigned long) (us*1.5);
|
||||
|
||||
has_highperf=QueryPerformanceFrequency(&freq);
|
||||
|
||||
//has_highperf=0; // debug
|
||||
|
||||
if (has_highperf) {
|
||||
QueryPerformanceCounter(&start);
|
||||
loopend.QuadPart=start.QuadPart+freq.QuadPart*us/(1000*1000);
|
||||
do {
|
||||
QueryPerformanceCounter(&stop);
|
||||
} while (stop.QuadPart<=loopend.QuadPart);
|
||||
}
|
||||
else {
|
||||
DEBUG_QueryPerformanceCounter(&start);
|
||||
|
||||
Sleep(1);
|
||||
Sleep( (DWORD)((us+999)/1000) );
|
||||
|
||||
DEBUG_QueryPerformanceCounter(&stop);
|
||||
}
|
||||
|
||||
DEBUG_DisplayTimingInfo(start, stop, freq, us, has_highperf);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif /* !HAVE_USLEEP */
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
318
src/safemode.c
Normal file
318
src/safemode.c
Normal file
@@ -0,0 +1,318 @@
|
||||
/*
|
||||
* avrdude - A Downloader/Uploader for AVR device programmers
|
||||
* avrdude is Copyright (C) 2000-2004 Brian S. Dean <bsd@bsdhome.com>
|
||||
*
|
||||
* This file: Copyright (C) 2005-2007 Colin O'Flynn <coflynn@newae.com>
|
||||
*
|
||||
* 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "ac_cfg.h"
|
||||
|
||||
#include "avrdude.h"
|
||||
#include "libavrdude.h"
|
||||
|
||||
/* This value from ac_cfg.h */
|
||||
/*
|
||||
* Writes the specified fuse in fusename (can be "lfuse", "hfuse", or
|
||||
* "efuse") and verifies it. Will try up to tries amount of times
|
||||
* before giving up
|
||||
*/
|
||||
int safemode_writefuse (unsigned char fuse, char * fusename, PROGRAMMER * pgm,
|
||||
AVRPART * p, int tries)
|
||||
{
|
||||
AVRMEM * m;
|
||||
unsigned char fuseread;
|
||||
int returnvalue = -1;
|
||||
|
||||
m = avr_locate_mem(p, fusename);
|
||||
if (m == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Keep trying to write then read back the fuse values */
|
||||
while (tries > 0) {
|
||||
if (avr_write_byte(pgm, p, m, 0, fuse) != 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if (pgm->read_byte(pgm, p, m, 0, &fuseread) != 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Report information to user if needed */
|
||||
avrdude_message(MSG_NOTICE, "%s: safemode: Wrote %s to %x, read as %x. %d attempts left\n",
|
||||
progname, fusename, fuse, fuseread, tries-1);
|
||||
|
||||
/* If fuse wrote OK, no need to keep going */
|
||||
if (fuse == fuseread) {
|
||||
tries = 0;
|
||||
returnvalue = 0;
|
||||
}
|
||||
tries--;
|
||||
}
|
||||
|
||||
return returnvalue;
|
||||
}
|
||||
|
||||
/*
|
||||
* Reads the fuses three times, checking that all readings are the
|
||||
* same. This will ensure that the before values aren't in error!
|
||||
*/
|
||||
int safemode_readfuses (unsigned char * lfuse, unsigned char * hfuse,
|
||||
unsigned char * efuse, unsigned char * fuse,
|
||||
PROGRAMMER * pgm, AVRPART * p)
|
||||
{
|
||||
|
||||
unsigned char value;
|
||||
unsigned char fusegood = 0;
|
||||
unsigned char allowfuseread = 1;
|
||||
unsigned char safemode_lfuse;
|
||||
unsigned char safemode_hfuse;
|
||||
unsigned char safemode_efuse;
|
||||
unsigned char safemode_fuse;
|
||||
AVRMEM * m;
|
||||
|
||||
safemode_lfuse = *lfuse;
|
||||
safemode_hfuse = *hfuse;
|
||||
safemode_efuse = *efuse;
|
||||
safemode_fuse = *fuse;
|
||||
|
||||
|
||||
/* Read fuse three times */
|
||||
fusegood = 2; /* If AVR device doesn't support this fuse, don't want
|
||||
to generate a verify error */
|
||||
m = avr_locate_mem(p, "fuse");
|
||||
if (m != NULL) {
|
||||
fusegood = 0; /* By default fuse is a failure */
|
||||
if(pgm->read_byte(pgm, p, m, 0, &safemode_fuse) != 0)
|
||||
{
|
||||
allowfuseread = 0;
|
||||
}
|
||||
avrdude_message(MSG_DEBUG, "%s: safemode read 1, fuse value: %x\n",progname, safemode_fuse);
|
||||
if(pgm->read_byte(pgm, p, m, 0, &value) != 0)
|
||||
{
|
||||
allowfuseread = 0;
|
||||
}
|
||||
avrdude_message(MSG_DEBUG, "%s: safemode read 2, fuse value: %x\n",progname, value);
|
||||
if (value == safemode_fuse) {
|
||||
if (pgm->read_byte(pgm, p, m, 0, &value) != 0)
|
||||
{
|
||||
allowfuseread = 0;
|
||||
}
|
||||
avrdude_message(MSG_DEBUG, "%s: safemode read 3, fuse value: %x\n",progname, value);
|
||||
if (value == safemode_fuse)
|
||||
{
|
||||
fusegood = 1; /* Fuse read OK three times */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//Programmer does not allow fuse reading.... no point trying anymore
|
||||
if (allowfuseread == 0)
|
||||
{
|
||||
return -5;
|
||||
}
|
||||
|
||||
if (fusegood == 0) {
|
||||
avrdude_message(MSG_INFO, "%s: safemode: Verify error - unable to read fuse properly. "
|
||||
"Programmer may not be reliable.\n", progname);
|
||||
return -1;
|
||||
}
|
||||
else if (fusegood == 1) {
|
||||
avrdude_message(MSG_NOTICE, "%s: safemode: fuse reads as %X\n", progname, safemode_fuse);
|
||||
}
|
||||
|
||||
|
||||
/* Read lfuse three times */
|
||||
fusegood = 2; /* If AVR device doesn't support this fuse, don't want
|
||||
to generate a verify error */
|
||||
m = avr_locate_mem(p, "lfuse");
|
||||
if (m != NULL) {
|
||||
fusegood = 0; /* By default fuse is a failure */
|
||||
if (pgm->read_byte(pgm, p, m, 0, &safemode_lfuse) != 0)
|
||||
{
|
||||
allowfuseread = 0;
|
||||
}
|
||||
avrdude_message(MSG_DEBUG, "%s: safemode read 1, lfuse value: %x\n",progname, safemode_lfuse);
|
||||
if (pgm->read_byte(pgm, p, m, 0, &value) != 0)
|
||||
{
|
||||
allowfuseread = 0;
|
||||
}
|
||||
avrdude_message(MSG_DEBUG, "%s: safemode read 2, lfuse value: %x\n",progname, value);
|
||||
if (value == safemode_lfuse) {
|
||||
if (pgm->read_byte(pgm, p, m, 0, &value) != 0)
|
||||
{
|
||||
allowfuseread = 0;
|
||||
}
|
||||
avrdude_message(MSG_DEBUG, "%s: safemode read 3, lfuse value: %x\n",progname, value);
|
||||
if (value == safemode_lfuse){
|
||||
fusegood = 1; /* Fuse read OK three times */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//Programmer does not allow fuse reading.... no point trying anymore
|
||||
if (allowfuseread == 0)
|
||||
{
|
||||
return -5;
|
||||
}
|
||||
|
||||
|
||||
if (fusegood == 0) {
|
||||
avrdude_message(MSG_INFO, "%s: safemode: Verify error - unable to read lfuse properly. "
|
||||
"Programmer may not be reliable.\n", progname);
|
||||
return -1;
|
||||
}
|
||||
else if (fusegood == 1) {
|
||||
avrdude_message(MSG_NOTICE, "%s: safemode: lfuse reads as %X\n", progname, safemode_lfuse);
|
||||
}
|
||||
|
||||
/* Read hfuse three times */
|
||||
fusegood = 2; /* If AVR device doesn't support this fuse, don't want
|
||||
to generate a verify error */
|
||||
m = avr_locate_mem(p, "hfuse");
|
||||
if (m != NULL) {
|
||||
fusegood = 0; /* By default fuse is a failure */
|
||||
if (pgm->read_byte(pgm, p, m, 0, &safemode_hfuse) != 0)
|
||||
{
|
||||
allowfuseread = 0;
|
||||
}
|
||||
avrdude_message(MSG_DEBUG, "%s: safemode read 1, hfuse value: %x\n",progname, safemode_hfuse);
|
||||
if (pgm->read_byte(pgm, p, m, 0, &value) != 0)
|
||||
{
|
||||
allowfuseread = 0;
|
||||
}
|
||||
avrdude_message(MSG_DEBUG, "%s: safemode read 2, hfuse value: %x\n",progname, value);
|
||||
if (value == safemode_hfuse) {
|
||||
if (pgm->read_byte(pgm, p, m, 0, &value) != 0)
|
||||
{
|
||||
allowfuseread = 0;
|
||||
}
|
||||
avrdude_message(MSG_DEBUG, "%s: safemode read 3, hfuse value: %x\n",progname, value);
|
||||
if (value == safemode_hfuse){
|
||||
fusegood = 1; /* Fuse read OK three times */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//Programmer does not allow fuse reading.... no point trying anymore
|
||||
if (allowfuseread == 0)
|
||||
{
|
||||
return -5;
|
||||
}
|
||||
|
||||
if (fusegood == 0) {
|
||||
avrdude_message(MSG_INFO, "%s: safemode: Verify error - unable to read hfuse properly. "
|
||||
"Programmer may not be reliable.\n", progname);
|
||||
return -2;
|
||||
}
|
||||
else if (fusegood == 1){
|
||||
avrdude_message(MSG_NOTICE, "%s: safemode: hfuse reads as %X\n", progname, safemode_hfuse);
|
||||
}
|
||||
|
||||
/* Read efuse three times */
|
||||
fusegood = 2; /* If AVR device doesn't support this fuse, don't want
|
||||
to generate a verify error */
|
||||
m = avr_locate_mem(p, "efuse");
|
||||
if (m != NULL) {
|
||||
fusegood = 0; /* By default fuse is a failure */
|
||||
if (pgm->read_byte(pgm, p, m, 0, &safemode_efuse) != 0)
|
||||
{
|
||||
allowfuseread = 0;
|
||||
}
|
||||
avrdude_message(MSG_DEBUG, "%s: safemode read 1, efuse value: %x\n",progname, safemode_efuse);
|
||||
if (pgm->read_byte(pgm, p, m, 0, &value) != 0)
|
||||
{
|
||||
allowfuseread = 0;
|
||||
}
|
||||
avrdude_message(MSG_DEBUG, "%s: safemode read 2, efuse value: %x\n",progname, value);
|
||||
if (value == safemode_efuse) {
|
||||
if (pgm->read_byte(pgm, p, m, 0, &value) != 0)
|
||||
{
|
||||
allowfuseread = 0;
|
||||
}
|
||||
avrdude_message(MSG_DEBUG, "%s: safemode read 3, efuse value: %x\n",progname, value);
|
||||
if (value == safemode_efuse){
|
||||
fusegood = 1; /* Fuse read OK three times */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//Programmer does not allow fuse reading.... no point trying anymore
|
||||
if (allowfuseread == 0)
|
||||
{
|
||||
return -5;
|
||||
}
|
||||
|
||||
if (fusegood == 0) {
|
||||
avrdude_message(MSG_INFO, "%s: safemode: Verify error - unable to read efuse properly. "
|
||||
"Programmer may not be reliable.\n", progname);
|
||||
return -3;
|
||||
}
|
||||
else if (fusegood == 1) {
|
||||
avrdude_message(MSG_NOTICE, "%s: safemode: efuse reads as %X\n", progname, safemode_efuse);
|
||||
}
|
||||
|
||||
*lfuse = safemode_lfuse;
|
||||
*hfuse = safemode_hfuse;
|
||||
*efuse = safemode_efuse;
|
||||
*fuse = safemode_fuse;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* This routine will store the current values pointed to by lfuse,
|
||||
* hfuse, and efuse into an internal buffer in this routine when save
|
||||
* is set to 1. When save is 0 (or not 1 really) it will copy the
|
||||
* values from the internal buffer into the locations pointed to be
|
||||
* lfuse, hfuse, and efuse. This allows you to change the fuse bits if
|
||||
* needed from another routine (ie: have it so if user requests fuse
|
||||
* bits are changed, the requested value is now verified
|
||||
*/
|
||||
int safemode_memfuses (int save, unsigned char * lfuse, unsigned char * hfuse,
|
||||
unsigned char * efuse, unsigned char * fuse)
|
||||
{
|
||||
static unsigned char safemode_lfuse = 0xff;
|
||||
static unsigned char safemode_hfuse = 0xff;
|
||||
static unsigned char safemode_efuse = 0xff;
|
||||
static unsigned char safemode_fuse = 0xff;
|
||||
|
||||
switch (save) {
|
||||
|
||||
/* Save the fuses as safemode setting */
|
||||
case 1:
|
||||
safemode_lfuse = *lfuse;
|
||||
safemode_hfuse = *hfuse;
|
||||
safemode_efuse = *efuse;
|
||||
safemode_fuse = *fuse;
|
||||
|
||||
break;
|
||||
/* Read back the fuses */
|
||||
default:
|
||||
*lfuse = safemode_lfuse;
|
||||
*hfuse = safemode_hfuse;
|
||||
*efuse = safemode_efuse;
|
||||
*fuse = safemode_fuse;
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
558
src/ser_avrdoper.c
Normal file
558
src/ser_avrdoper.c
Normal file
@@ -0,0 +1,558 @@
|
||||
/*
|
||||
* avrdude - A Downloader/Uploader for AVR device programmers
|
||||
* Copyright (C) 2003-2004 Theodore A. Roth <troth@openavr.org>
|
||||
* Copyright (C) 2006 Joerg Wunsch <j@uriah.heep.sax.de>
|
||||
* Copyright (C) 2006 Christian Starkjohann
|
||||
*
|
||||
* 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/* $Id$ */
|
||||
|
||||
/*
|
||||
* Serial Interface emulation for USB programmer "AVR-Doper" in HID mode.
|
||||
*/
|
||||
|
||||
#include "ac_cfg.h"
|
||||
|
||||
#if defined(HAVE_LIBHIDAPI) || (defined(WIN32NATIVE) && defined(HAVE_LIBHID))
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "avrdude.h"
|
||||
#include "libavrdude.h"
|
||||
|
||||
/* ------------------------------------------------------------------------ */
|
||||
|
||||
/* Numeric constants for 'reportType' parameters */
|
||||
#define USB_HID_REPORT_TYPE_INPUT 1
|
||||
#define USB_HID_REPORT_TYPE_OUTPUT 2
|
||||
#define USB_HID_REPORT_TYPE_FEATURE 3
|
||||
|
||||
/* These are the error codes which can be returned by functions of this
|
||||
* module.
|
||||
*/
|
||||
#define USB_ERROR_NONE 0
|
||||
#define USB_ERROR_ACCESS 1
|
||||
#define USB_ERROR_NOTFOUND 2
|
||||
#define USB_ERROR_BUSY 16
|
||||
#define USB_ERROR_IO 5
|
||||
|
||||
#define USB_VENDOR_ID 0x16c0
|
||||
#define USB_PRODUCT_ID 0x05df
|
||||
|
||||
static int reportDataSizes[4] = {13, 29, 61, 125};
|
||||
|
||||
static unsigned char avrdoperRxBuffer[280]; /* buffer for receive data */
|
||||
static int avrdoperRxLength = 0; /* amount of valid bytes in rx buffer */
|
||||
static int avrdoperRxPosition = 0; /* amount of bytes already consumed in rx buffer */
|
||||
|
||||
/* ------------------------------------------------------------------------ */
|
||||
/* ------------------------------------------------------------------------ */
|
||||
/* ------------------------------------------------------------------------ */
|
||||
|
||||
#if defined(HAVE_LIBHIDAPI)
|
||||
|
||||
#include <hidapi/hidapi.h>
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
static int usbOpenDevice(union filedescriptor *fdp, int vendor, char *vendorName,
|
||||
int product, char *productName, int doReportIDs)
|
||||
{
|
||||
hid_device *dev;
|
||||
|
||||
dev = hid_open(vendor, product, NULL);
|
||||
if (dev == NULL)
|
||||
{
|
||||
avrdude_message(MSG_INFO, "%s: usbOpenDevice(): No device found\n",
|
||||
progname);
|
||||
return USB_ERROR_NOTFOUND;
|
||||
}
|
||||
fdp->usb.handle = dev;
|
||||
return USB_ERROR_NONE;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
static void usbCloseDevice(union filedescriptor *fdp)
|
||||
{
|
||||
hid_device *udev = (hid_device *)fdp->usb.handle;
|
||||
fdp->usb.handle = NULL;
|
||||
|
||||
if (udev == NULL)
|
||||
return;
|
||||
|
||||
hid_close(udev);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
static int usbSetReport(union filedescriptor *fdp, int reportType, char *buffer, int len)
|
||||
{
|
||||
hid_device *udev = (hid_device *)fdp->usb.handle;
|
||||
int bytesSent = -1;
|
||||
|
||||
switch(reportType){
|
||||
case USB_HID_REPORT_TYPE_INPUT:
|
||||
break;
|
||||
case USB_HID_REPORT_TYPE_OUTPUT:
|
||||
bytesSent = hid_write(udev, (unsigned char*) buffer, len);
|
||||
break;
|
||||
case USB_HID_REPORT_TYPE_FEATURE:
|
||||
bytesSent = hid_send_feature_report(udev, (unsigned char*) buffer, len);
|
||||
break;
|
||||
}
|
||||
|
||||
if(bytesSent != len){
|
||||
if(bytesSent < 0)
|
||||
avrdude_message(MSG_INFO, "Error sending message: %s\n", hid_error(udev));
|
||||
return USB_ERROR_IO;
|
||||
}
|
||||
return USB_ERROR_NONE;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
static int usbGetReport(union filedescriptor *fdp, int reportType, int reportNumber,
|
||||
char *buffer, int *len)
|
||||
{
|
||||
hid_device *udev = (hid_device *)fdp->usb.handle;
|
||||
int bytesReceived = -1;
|
||||
|
||||
switch(reportType){
|
||||
case USB_HID_REPORT_TYPE_INPUT:
|
||||
bytesReceived = hid_read_timeout(udev, (unsigned char*) buffer, *len, 300);
|
||||
break;
|
||||
case USB_HID_REPORT_TYPE_OUTPUT:
|
||||
break;
|
||||
case USB_HID_REPORT_TYPE_FEATURE:
|
||||
bytesReceived = hid_get_feature_report(udev, (unsigned char*) buffer, *len);
|
||||
break;
|
||||
}
|
||||
if(bytesReceived < 0){
|
||||
avrdude_message(MSG_INFO, "Error sending message: %s\n", hid_error(udev));
|
||||
return USB_ERROR_IO;
|
||||
}
|
||||
*len = bytesReceived;
|
||||
return USB_ERROR_NONE;
|
||||
}
|
||||
/* ------------------------------------------------------------------------ */
|
||||
/* ------------------------------------------------------------------------ */
|
||||
/* ------------------------------------------------------------------------ */
|
||||
|
||||
#else /* !defined(HAVE_LIBHIDAPI) */
|
||||
|
||||
/* ------------------------------------------------------------------------ */
|
||||
/* ------------------------------------------------------------------------ */
|
||||
/* ------------------------------------------------------------------------ */
|
||||
|
||||
|
||||
#include <windows.h>
|
||||
#include <setupapi.h>
|
||||
|
||||
#if defined(HAVE_DDK_HIDSDI_H)
|
||||
# include <ddk/hidsdi.h>
|
||||
#else
|
||||
# include "my_ddk_hidsdi.h"
|
||||
#endif
|
||||
#include <ddk/hidpi.h>
|
||||
|
||||
#ifdef USB_DEBUG
|
||||
#define DEBUG_PRINT(arg) printf arg
|
||||
#else
|
||||
#define DEBUG_PRINT(arg)
|
||||
#endif
|
||||
|
||||
/* ------------------------------------------------------------------------ */
|
||||
|
||||
static void convertUniToAscii(char *buffer)
|
||||
{
|
||||
unsigned short *uni = (void *)buffer;
|
||||
char *ascii = buffer;
|
||||
|
||||
while(*uni != 0){
|
||||
if(*uni >= 256){
|
||||
*ascii++ = '?';
|
||||
uni++;
|
||||
}else{
|
||||
*ascii++ = *uni++;
|
||||
}
|
||||
}
|
||||
*ascii++ = 0;
|
||||
}
|
||||
|
||||
static int usbOpenDevice(union filedescriptor *fdp, int vendor, char *vendorName,
|
||||
int product, char *productName, int usesReportIDs)
|
||||
{
|
||||
GUID hidGuid; /* GUID for HID driver */
|
||||
HDEVINFO deviceInfoList;
|
||||
SP_DEVICE_INTERFACE_DATA deviceInfo;
|
||||
SP_DEVICE_INTERFACE_DETAIL_DATA *deviceDetails = NULL;
|
||||
DWORD size;
|
||||
int i, openFlag = 0; /* may be FILE_FLAG_OVERLAPPED */
|
||||
int errorCode = USB_ERROR_NOTFOUND;
|
||||
HANDLE handle = INVALID_HANDLE_VALUE;
|
||||
HIDD_ATTRIBUTES deviceAttributes;
|
||||
|
||||
HidD_GetHidGuid(&hidGuid);
|
||||
deviceInfoList = SetupDiGetClassDevs(&hidGuid, NULL, NULL,
|
||||
DIGCF_PRESENT | DIGCF_INTERFACEDEVICE);
|
||||
deviceInfo.cbSize = sizeof(deviceInfo);
|
||||
for(i=0;;i++){
|
||||
if(handle != INVALID_HANDLE_VALUE){
|
||||
CloseHandle(handle);
|
||||
handle = INVALID_HANDLE_VALUE;
|
||||
}
|
||||
if(!SetupDiEnumDeviceInterfaces(deviceInfoList, 0, &hidGuid, i, &deviceInfo))
|
||||
break; /* no more entries */
|
||||
/* first do a dummy call just to determine the actual size required */
|
||||
SetupDiGetDeviceInterfaceDetail(deviceInfoList, &deviceInfo, NULL, 0, &size, NULL);
|
||||
if(deviceDetails != NULL)
|
||||
free(deviceDetails);
|
||||
deviceDetails = malloc(size);
|
||||
deviceDetails->cbSize = sizeof(*deviceDetails);
|
||||
/* this call is for real: */
|
||||
SetupDiGetDeviceInterfaceDetail(deviceInfoList, &deviceInfo, deviceDetails,
|
||||
size, &size, NULL);
|
||||
DEBUG_PRINT(("checking HID path \"%s\"\n", deviceDetails->DevicePath));
|
||||
/* attempt opening for R/W -- we don't care about devices which can't be accessed */
|
||||
handle = CreateFile(deviceDetails->DevicePath, GENERIC_READ|GENERIC_WRITE,
|
||||
FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING,
|
||||
openFlag, NULL);
|
||||
if(handle == INVALID_HANDLE_VALUE){
|
||||
DEBUG_PRINT(("opening failed: %d\n", (int)GetLastError()));
|
||||
/* errorCode = USB_ERROR_ACCESS; opening will always fail for mouse -- ignore */
|
||||
continue;
|
||||
}
|
||||
deviceAttributes.Size = sizeof(deviceAttributes);
|
||||
HidD_GetAttributes(handle, &deviceAttributes);
|
||||
DEBUG_PRINT(("device attributes: vid=%d pid=%d\n",
|
||||
deviceAttributes.VendorID, deviceAttributes.ProductID));
|
||||
if(deviceAttributes.VendorID != vendor || deviceAttributes.ProductID != product)
|
||||
continue; /* ignore this device */
|
||||
errorCode = USB_ERROR_NOTFOUND;
|
||||
if(vendorName != NULL && productName != NULL){
|
||||
char buffer[512];
|
||||
if(!HidD_GetManufacturerString(handle, buffer, sizeof(buffer))){
|
||||
DEBUG_PRINT(("error obtaining vendor name\n"));
|
||||
errorCode = USB_ERROR_IO;
|
||||
continue;
|
||||
}
|
||||
convertUniToAscii(buffer);
|
||||
DEBUG_PRINT(("vendorName = \"%s\"\n", buffer));
|
||||
if(strcmp(vendorName, buffer) != 0)
|
||||
continue;
|
||||
if(!HidD_GetProductString(handle, buffer, sizeof(buffer))){
|
||||
DEBUG_PRINT(("error obtaining product name\n"));
|
||||
errorCode = USB_ERROR_IO;
|
||||
continue;
|
||||
}
|
||||
convertUniToAscii(buffer);
|
||||
DEBUG_PRINT(("productName = \"%s\"\n", buffer));
|
||||
if(strcmp(productName, buffer) != 0)
|
||||
continue;
|
||||
}
|
||||
break; /* we have found the device we are looking for! */
|
||||
}
|
||||
SetupDiDestroyDeviceInfoList(deviceInfoList);
|
||||
if(deviceDetails != NULL)
|
||||
free(deviceDetails);
|
||||
if(handle != INVALID_HANDLE_VALUE){
|
||||
fdp->pfd = (void *)handle;
|
||||
errorCode = 0;
|
||||
}
|
||||
return errorCode;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------ */
|
||||
|
||||
static void usbCloseDevice(union filedescriptor *fdp)
|
||||
{
|
||||
CloseHandle((HANDLE)fdp->pfd);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------ */
|
||||
|
||||
static int usbSetReport(union filedescriptor *fdp, int reportType, char *buffer, int len)
|
||||
{
|
||||
HANDLE handle = (HANDLE)fdp->pfd;
|
||||
BOOLEAN rval = 0;
|
||||
DWORD bytesWritten;
|
||||
|
||||
switch(reportType){
|
||||
case USB_HID_REPORT_TYPE_INPUT:
|
||||
break;
|
||||
case USB_HID_REPORT_TYPE_OUTPUT:
|
||||
rval = WriteFile(handle, buffer, len, &bytesWritten, NULL);
|
||||
break;
|
||||
case USB_HID_REPORT_TYPE_FEATURE:
|
||||
rval = HidD_SetFeature(handle, buffer, len);
|
||||
break;
|
||||
}
|
||||
return rval == 0 ? USB_ERROR_IO : 0;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------ */
|
||||
|
||||
static int usbGetReport(union filedescriptor *fdp, int reportType, int reportNumber,
|
||||
char *buffer, int *len)
|
||||
{
|
||||
HANDLE handle = (HANDLE)fdp->pfd;
|
||||
BOOLEAN rval = 0;
|
||||
DWORD bytesRead;
|
||||
|
||||
switch(reportType){
|
||||
case USB_HID_REPORT_TYPE_INPUT:
|
||||
buffer[0] = reportNumber;
|
||||
rval = ReadFile(handle, buffer, *len, &bytesRead, NULL);
|
||||
if(rval)
|
||||
*len = bytesRead;
|
||||
break;
|
||||
case USB_HID_REPORT_TYPE_OUTPUT:
|
||||
break;
|
||||
case USB_HID_REPORT_TYPE_FEATURE:
|
||||
buffer[0] = reportNumber;
|
||||
rval = HidD_GetFeature(handle, buffer, *len);
|
||||
break;
|
||||
}
|
||||
return rval == 0 ? USB_ERROR_IO : 0;
|
||||
}
|
||||
|
||||
#endif /* WIN32NATIVE */
|
||||
|
||||
/* ------------------------------------------------------------------------ */
|
||||
/* ------------------------------------------------------------------------ */
|
||||
/* ------------------------------------------------------------------------ */
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
static void dumpBlock(const char *prefix, const unsigned char *buf, int len)
|
||||
{
|
||||
int i;
|
||||
|
||||
if(len <= 8){ /* more compact format for short blocks */
|
||||
avrdude_message(MSG_INFO, "%s: %d bytes: ", prefix, len);
|
||||
for(i = 0; i < len; i++){
|
||||
avrdude_message(MSG_INFO, "%02x ", buf[i]);
|
||||
}
|
||||
avrdude_message(MSG_INFO, " \"");
|
||||
for(i = 0; i < len; i++){
|
||||
if(buf[i] >= 0x20 && buf[i] < 0x7f){
|
||||
fputc(buf[i], stderr);
|
||||
}else{
|
||||
fputc('.', stderr);
|
||||
}
|
||||
}
|
||||
avrdude_message(MSG_INFO, "\"\n");
|
||||
}else{
|
||||
avrdude_message(MSG_INFO, "%s: %d bytes:\n", prefix, len);
|
||||
while(len > 0){
|
||||
for(i = 0; i < 16; i++){
|
||||
if(i < len){
|
||||
avrdude_message(MSG_INFO, "%02x ", buf[i]);
|
||||
}else{
|
||||
avrdude_message(MSG_INFO, " ");
|
||||
}
|
||||
if(i == 7)
|
||||
fputc(' ', stderr);
|
||||
}
|
||||
avrdude_message(MSG_INFO, " \"");
|
||||
for(i = 0; i < 16; i++){
|
||||
if(i < len){
|
||||
if(buf[i] >= 0x20 && buf[i] < 0x7f){
|
||||
fputc(buf[i], stderr);
|
||||
}else{
|
||||
fputc('.', stderr);
|
||||
}
|
||||
}
|
||||
}
|
||||
avrdude_message(MSG_INFO, "\"\n");
|
||||
buf += 16;
|
||||
len -= 16;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static char *usbErrorText(int usbErrno)
|
||||
{
|
||||
static char buffer[32];
|
||||
|
||||
switch(usbErrno){
|
||||
case USB_ERROR_NONE: return "Success.";
|
||||
case USB_ERROR_ACCESS: return "Access denied.";
|
||||
case USB_ERROR_NOTFOUND:return "Device not found.";
|
||||
case USB_ERROR_BUSY: return "Device is busy.";
|
||||
case USB_ERROR_IO: return "I/O Error.";
|
||||
default:
|
||||
sprintf(buffer, "Unknown error %d.", usbErrno);
|
||||
return buffer;
|
||||
}
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
static int avrdoper_open(char *port, union pinfo pinfo, union filedescriptor *fdp)
|
||||
{
|
||||
int rval;
|
||||
char *vname = "obdev.at";
|
||||
char *devname = "AVR-Doper";
|
||||
|
||||
rval = usbOpenDevice(fdp, USB_VENDOR_ID, vname, USB_PRODUCT_ID, devname, 1);
|
||||
if(rval != 0){
|
||||
avrdude_message(MSG_INFO, "%s: avrdoper_open(): %s\n", progname, usbErrorText(rval));
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
static void avrdoper_close(union filedescriptor *fdp)
|
||||
{
|
||||
usbCloseDevice(fdp);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
static int chooseDataSize(int len)
|
||||
{
|
||||
int i;
|
||||
|
||||
for(i = 0; i < sizeof(reportDataSizes)/sizeof(reportDataSizes[0]); i++){
|
||||
if(reportDataSizes[i] >= len)
|
||||
return i;
|
||||
}
|
||||
return i - 1;
|
||||
}
|
||||
|
||||
static int avrdoper_send(union filedescriptor *fdp, const unsigned char *buf, size_t buflen)
|
||||
{
|
||||
if(verbose > 3)
|
||||
dumpBlock("Send", buf, buflen);
|
||||
while(buflen > 0){
|
||||
unsigned char buffer[256];
|
||||
int rval, lenIndex = chooseDataSize(buflen);
|
||||
int thisLen = buflen > reportDataSizes[lenIndex] ?
|
||||
reportDataSizes[lenIndex] : buflen;
|
||||
buffer[0] = lenIndex + 1; /* report ID */
|
||||
buffer[1] = thisLen;
|
||||
memcpy(buffer + 2, buf, thisLen);
|
||||
avrdude_message(MSG_TRACE, "Sending %d bytes data chunk\n", thisLen);
|
||||
rval = usbSetReport(fdp, USB_HID_REPORT_TYPE_FEATURE, (char *)buffer,
|
||||
reportDataSizes[lenIndex] + 2);
|
||||
if(rval != 0){
|
||||
avrdude_message(MSG_INFO, "%s: avrdoper_send(): %s\n", progname, usbErrorText(rval));
|
||||
return -1;
|
||||
}
|
||||
buflen -= thisLen;
|
||||
buf += thisLen;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
static int avrdoperFillBuffer(union filedescriptor *fdp)
|
||||
{
|
||||
int bytesPending = reportDataSizes[1]; /* guess how much data is buffered in device */
|
||||
|
||||
avrdoperRxPosition = avrdoperRxLength = 0;
|
||||
while(bytesPending > 0){
|
||||
int len, usbErr, lenIndex = chooseDataSize(bytesPending);
|
||||
unsigned char buffer[128];
|
||||
len = sizeof(avrdoperRxBuffer) - avrdoperRxLength; /* bytes remaining */
|
||||
if(reportDataSizes[lenIndex] + 2 > len) /* requested data would not fit into buffer */
|
||||
break;
|
||||
len = reportDataSizes[lenIndex] + 2;
|
||||
usbErr = usbGetReport(fdp, USB_HID_REPORT_TYPE_FEATURE, lenIndex + 1,
|
||||
(char *)buffer, &len);
|
||||
if(usbErr != 0){
|
||||
avrdude_message(MSG_INFO, "%s: avrdoperFillBuffer(): %s\n", progname, usbErrorText(usbErr));
|
||||
return -1;
|
||||
}
|
||||
avrdude_message(MSG_TRACE, "Received %d bytes data chunk of total %d\n", len - 2, buffer[1]);
|
||||
len -= 2; /* compensate for report ID and length byte */
|
||||
bytesPending = buffer[1] - len; /* amount still buffered */
|
||||
if(len > buffer[1]) /* cut away padding */
|
||||
len = buffer[1];
|
||||
if(avrdoperRxLength + len > sizeof(avrdoperRxBuffer)){
|
||||
avrdude_message(MSG_INFO, "%s: avrdoperFillBuffer(): internal error: buffer overflow\n",
|
||||
progname);
|
||||
return -1;
|
||||
}
|
||||
memcpy(avrdoperRxBuffer + avrdoperRxLength, buffer + 2, len);
|
||||
avrdoperRxLength += len;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int avrdoper_recv(union filedescriptor *fdp, unsigned char *buf, size_t buflen)
|
||||
{
|
||||
unsigned char *p = buf;
|
||||
int remaining = buflen;
|
||||
|
||||
while(remaining > 0){
|
||||
int len, available = avrdoperRxLength - avrdoperRxPosition;
|
||||
if(available <= 0){ /* buffer is empty */
|
||||
if (avrdoperFillBuffer(fdp) < 0)
|
||||
return -1;
|
||||
continue;
|
||||
}
|
||||
len = remaining < available ? remaining : available;
|
||||
memcpy(p, avrdoperRxBuffer + avrdoperRxPosition, len);
|
||||
p += len;
|
||||
remaining -= len;
|
||||
avrdoperRxPosition += len;
|
||||
}
|
||||
if(verbose > 3)
|
||||
dumpBlock("Receive", buf, buflen);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
static int avrdoper_drain(union filedescriptor *fdp, int display)
|
||||
{
|
||||
do{
|
||||
if (avrdoperFillBuffer(fdp) < 0)
|
||||
return -1;
|
||||
}while(avrdoperRxLength > 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
static int avrdoper_set_dtr_rts(union filedescriptor *fdp, int is_on)
|
||||
{
|
||||
avrdude_message(MSG_INFO, "%s: AVR-Doper doesn't support DTR/RTS setting\n", progname);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
struct serial_device avrdoper_serdev =
|
||||
{
|
||||
.open = avrdoper_open,
|
||||
.close = avrdoper_close,
|
||||
.send = avrdoper_send,
|
||||
.recv = avrdoper_recv,
|
||||
.drain = avrdoper_drain,
|
||||
.set_dtr_rts = avrdoper_set_dtr_rts,
|
||||
.flags = SERDEV_FL_NONE,
|
||||
};
|
||||
|
||||
#endif /* defined(HAVE_LIBHIDAPI) || (defined(WIN32NATIVE) && defined(HAVE_LIBHID)) */
|
||||
529
src/ser_posix.c
Normal file
529
src/ser_posix.c
Normal file
@@ -0,0 +1,529 @@
|
||||
/*
|
||||
* avrdude - A Downloader/Uploader for AVR device programmers
|
||||
* Copyright (C) 2003-2004 Theodore A. Roth <troth@openavr.org>
|
||||
* Copyright (C) 2006 Joerg Wunsch <j@uriah.heep.sax.de>
|
||||
*
|
||||
* 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/* $Id$ */
|
||||
|
||||
/*
|
||||
* Posix serial interface for avrdude.
|
||||
*/
|
||||
|
||||
#if !defined(WIN32NATIVE)
|
||||
|
||||
#include "ac_cfg.h"
|
||||
|
||||
#include <ctype.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netdb.h>
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <termios.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "avrdude.h"
|
||||
#include "libavrdude.h"
|
||||
|
||||
long serial_recv_timeout = 5000; /* ms */
|
||||
|
||||
struct baud_mapping {
|
||||
long baud;
|
||||
speed_t speed;
|
||||
};
|
||||
|
||||
/* There are a lot more baud rates we could handle, but what's the point? */
|
||||
|
||||
static struct baud_mapping baud_lookup_table [] = {
|
||||
{ 300, B300 },
|
||||
{ 600, B600 },
|
||||
{ 1200, B1200 },
|
||||
{ 2400, B2400 },
|
||||
{ 4800, B4800 },
|
||||
{ 9600, B9600 },
|
||||
{ 19200, B19200 },
|
||||
{ 38400, B38400 },
|
||||
#ifdef B57600
|
||||
{ 57600, B57600 },
|
||||
#endif
|
||||
#ifdef B115200
|
||||
{ 115200, B115200 },
|
||||
#endif
|
||||
#ifdef B230400
|
||||
{ 230400, B230400 },
|
||||
#endif
|
||||
{ 0, 0 } /* Terminator. */
|
||||
};
|
||||
|
||||
static struct termios original_termios;
|
||||
static int saved_original_termios;
|
||||
|
||||
static speed_t serial_baud_lookup(long baud)
|
||||
{
|
||||
struct baud_mapping *map = baud_lookup_table;
|
||||
|
||||
while (map->baud) {
|
||||
if (map->baud == baud)
|
||||
return map->speed;
|
||||
map++;
|
||||
}
|
||||
|
||||
/*
|
||||
* If a non-standard BAUD rate is used, issue
|
||||
* a warning (if we are verbose) and return the raw rate
|
||||
*/
|
||||
avrdude_message(MSG_NOTICE, "%s: serial_baud_lookup(): Using non-standard baud rate: %ld",
|
||||
progname, baud);
|
||||
|
||||
return baud;
|
||||
}
|
||||
|
||||
static tcflag_t translate_flags(unsigned long cflags)
|
||||
{
|
||||
return ((cflags & SERIAL_CS5) ? CS5 : 0) |
|
||||
((cflags & SERIAL_CS6) ? CS6 : 0) |
|
||||
((cflags & SERIAL_CS7) ? CS7 : 0) |
|
||||
((cflags & SERIAL_CS8) ? CS8 : 0) |
|
||||
((cflags & SERIAL_CSTOPB) ? CSTOPB : 0) |
|
||||
((cflags & SERIAL_CREAD) ? CREAD : 0) |
|
||||
((cflags & (SERIAL_PARENB | SERIAL_PARODD)) ? PARENB : 0) |
|
||||
((cflags & SERIAL_PARODD) ? PARODD : 0) |
|
||||
((cflags & SERIAL_CLOCAL) ? CLOCAL : 0) ;
|
||||
}
|
||||
|
||||
static int ser_setparams(union filedescriptor *fd, long baud, unsigned long cflags)
|
||||
{
|
||||
int rc;
|
||||
struct termios termios;
|
||||
speed_t speed = serial_baud_lookup (baud);
|
||||
|
||||
if (!isatty(fd->ifd))
|
||||
return -ENOTTY;
|
||||
|
||||
/*
|
||||
* initialize terminal modes
|
||||
*/
|
||||
rc = tcgetattr(fd->ifd, &termios);
|
||||
if (rc < 0) {
|
||||
avrdude_message(MSG_INFO, "%s: ser_setparams(): tcgetattr() failed",
|
||||
progname);
|
||||
return -errno;
|
||||
}
|
||||
|
||||
/*
|
||||
* copy termios for ser_close if we haven't already
|
||||
*/
|
||||
if (! saved_original_termios++) {
|
||||
original_termios = termios;
|
||||
}
|
||||
|
||||
termios.c_iflag = IGNBRK;
|
||||
termios.c_oflag = 0;
|
||||
termios.c_lflag = 0;
|
||||
termios.c_cflag = translate_flags(cflags);
|
||||
termios.c_cc[VMIN] = 1;
|
||||
termios.c_cc[VTIME] = 0;
|
||||
|
||||
cfsetospeed(&termios, speed);
|
||||
cfsetispeed(&termios, speed);
|
||||
|
||||
rc = tcsetattr(fd->ifd, TCSANOW, &termios);
|
||||
if (rc < 0) {
|
||||
avrdude_message(MSG_INFO, "%s: ser_setparams(): tcsetattr() failed\n",
|
||||
progname);
|
||||
return -errno;
|
||||
}
|
||||
|
||||
/*
|
||||
* Everything is now set up for a local line without modem control
|
||||
* or flow control, so clear O_NONBLOCK again.
|
||||
*/
|
||||
rc = fcntl(fd->ifd, F_GETFL, 0);
|
||||
if (rc != -1)
|
||||
fcntl(fd->ifd, F_SETFL, rc & ~O_NONBLOCK);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Given a port description of the form <host>:<port>, open a TCP
|
||||
* connection to the specified destination, which is assumed to be a
|
||||
* terminal/console server with serial parameters configured
|
||||
* appropriately (e. g. 115200-8-N-1 for a STK500.)
|
||||
*/
|
||||
static int
|
||||
net_open(const char *port, union filedescriptor *fdp)
|
||||
{
|
||||
#ifdef HAVE_GETADDRINFO
|
||||
char *hp, *hstr, *pstr;
|
||||
int s, fd, ret = -1;
|
||||
struct addrinfo hints;
|
||||
struct addrinfo *result, *rp;
|
||||
|
||||
if ((hstr = hp = strdup(port)) == NULL) {
|
||||
avrdude_message(MSG_INFO, "%s: net_open(): Out of memory!\n",
|
||||
progname);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* As numeric IPv6 addresses use colons as separators, we need to
|
||||
* look for the last colon here, which separates the port number or
|
||||
* service name from the host or IP address.
|
||||
*/
|
||||
if (((pstr = strrchr(hstr, ':')) == NULL) || (pstr == hstr)) {
|
||||
avrdude_message(MSG_INFO, "%s: net_open(): Mangled host:port string \"%s\"\n",
|
||||
progname, hstr);
|
||||
goto error;
|
||||
}
|
||||
|
||||
/*
|
||||
* Remove brackets from the host part, if present.
|
||||
*/
|
||||
if (*hstr == '[' && *(pstr-1) == ']') {
|
||||
hstr++;
|
||||
*(pstr-1) = '\0';
|
||||
}
|
||||
|
||||
/*
|
||||
* Terminate the host section of the description.
|
||||
*/
|
||||
*pstr++ = '\0';
|
||||
|
||||
memset(&hints, 0, sizeof(hints));
|
||||
hints.ai_family = AF_UNSPEC;
|
||||
hints.ai_socktype = SOCK_STREAM;
|
||||
s = getaddrinfo(hstr, pstr, &hints, &result);
|
||||
|
||||
if (s != 0) {
|
||||
avrdude_message(MSG_INFO,
|
||||
"%s: net_open(): Cannot resolve "
|
||||
"host=\"%s\", port=\"%s\": %s\n",
|
||||
progname, hstr, pstr, gai_strerror(s));
|
||||
goto error;
|
||||
}
|
||||
for (rp = result; rp != NULL; rp = rp->ai_next) {
|
||||
fd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
|
||||
if (fd == -1) {
|
||||
/* This one failed, loop over */
|
||||
continue;
|
||||
}
|
||||
if (connect(fd, rp->ai_addr, rp->ai_addrlen) != -1) {
|
||||
/* Success, we are connected */
|
||||
break;
|
||||
}
|
||||
close(fd);
|
||||
}
|
||||
if (rp == NULL) {
|
||||
avrdude_message(MSG_INFO, "%s: net_open(): Cannot connect: %s\n",
|
||||
progname, strerror(errno));
|
||||
}
|
||||
else {
|
||||
fdp->ifd = fd;
|
||||
ret = 0;
|
||||
}
|
||||
freeaddrinfo(result);
|
||||
|
||||
error:
|
||||
free(hp);
|
||||
return ret;
|
||||
#else
|
||||
avrdude_message(MSG_INFO,
|
||||
"%s: Networking is not supported on your platform.\n"
|
||||
"If you need it, please open a bug report.\n", progname);
|
||||
return -1;
|
||||
#endif /* HAVE_GETADDRINFO */
|
||||
}
|
||||
|
||||
|
||||
static int ser_set_dtr_rts(union filedescriptor *fdp, int is_on)
|
||||
{
|
||||
unsigned int ctl;
|
||||
int r;
|
||||
|
||||
r = ioctl(fdp->ifd, TIOCMGET, &ctl);
|
||||
if (r < 0) {
|
||||
perror("ioctl(\"TIOCMGET\")");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (is_on) {
|
||||
/* Set DTR and RTS */
|
||||
ctl |= (TIOCM_DTR | TIOCM_RTS);
|
||||
}
|
||||
else {
|
||||
/* Clear DTR and RTS */
|
||||
ctl &= ~(TIOCM_DTR | TIOCM_RTS);
|
||||
}
|
||||
|
||||
r = ioctl(fdp->ifd, TIOCMSET, &ctl);
|
||||
if (r < 0) {
|
||||
perror("ioctl(\"TIOCMSET\")");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ser_open(char * port, union pinfo pinfo, union filedescriptor *fdp)
|
||||
{
|
||||
int rc;
|
||||
int fd;
|
||||
|
||||
/*
|
||||
* If the port is of the form "net:<host>:<port>", then
|
||||
* handle it as a TCP connection to a terminal server.
|
||||
*/
|
||||
if (strncmp(port, "net:", strlen("net:")) == 0) {
|
||||
return net_open(port + strlen("net:"), fdp);
|
||||
}
|
||||
|
||||
/*
|
||||
* open the serial port
|
||||
*/
|
||||
fd = open(port, O_RDWR | O_NOCTTY | O_NONBLOCK);
|
||||
if (fd < 0) {
|
||||
avrdude_message(MSG_INFO, "%s: ser_open(): can't open device \"%s\": %s\n",
|
||||
progname, port, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
fdp->ifd = fd;
|
||||
|
||||
/*
|
||||
* set serial line attributes
|
||||
*/
|
||||
rc = ser_setparams(fdp, pinfo.serialinfo.baud, pinfo.serialinfo.cflags);
|
||||
if (rc) {
|
||||
avrdude_message(MSG_INFO, "%s: ser_open(): can't set attributes for device \"%s\": %s\n",
|
||||
progname, port, strerror(-rc));
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ser_close(union filedescriptor *fd)
|
||||
{
|
||||
/*
|
||||
* restore original termios settings from ser_open
|
||||
*/
|
||||
if (saved_original_termios) {
|
||||
int rc = tcsetattr(fd->ifd, TCSANOW | TCSADRAIN, &original_termios);
|
||||
if (rc) {
|
||||
avrdude_message(MSG_INFO, "%s: ser_close(): can't reset attributes for device: %s\n",
|
||||
progname, strerror(errno));
|
||||
}
|
||||
saved_original_termios = 0;
|
||||
}
|
||||
|
||||
close(fd->ifd);
|
||||
}
|
||||
|
||||
|
||||
static int ser_send(union filedescriptor *fd, const unsigned char * buf, size_t buflen)
|
||||
{
|
||||
int rc;
|
||||
const unsigned char * p = buf;
|
||||
size_t len = buflen;
|
||||
|
||||
if (!len)
|
||||
return 0;
|
||||
|
||||
if (verbose > 3)
|
||||
{
|
||||
avrdude_message(MSG_TRACE, "%s: Send: ", progname);
|
||||
|
||||
while (buflen) {
|
||||
unsigned char c = *buf;
|
||||
if (isprint(c)) {
|
||||
avrdude_message(MSG_TRACE, "%c ", c);
|
||||
}
|
||||
else {
|
||||
avrdude_message(MSG_TRACE, ". ");
|
||||
}
|
||||
avrdude_message(MSG_TRACE, "[%02x] ", c);
|
||||
|
||||
buf++;
|
||||
buflen--;
|
||||
}
|
||||
|
||||
avrdude_message(MSG_TRACE, "\n");
|
||||
}
|
||||
|
||||
while (len) {
|
||||
rc = write(fd->ifd, p, (len > 1024) ? 1024 : len);
|
||||
if (rc < 0) {
|
||||
avrdude_message(MSG_INFO, "%s: ser_send(): write error: %s\n",
|
||||
progname, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
p += rc;
|
||||
len -= rc;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int ser_recv(union filedescriptor *fd, unsigned char * buf, size_t buflen)
|
||||
{
|
||||
struct timeval timeout, to2;
|
||||
fd_set rfds;
|
||||
int nfds;
|
||||
int rc;
|
||||
unsigned char * p = buf;
|
||||
size_t len = 0;
|
||||
|
||||
timeout.tv_sec = serial_recv_timeout / 1000L;
|
||||
timeout.tv_usec = (serial_recv_timeout % 1000L) * 1000;
|
||||
to2 = timeout;
|
||||
|
||||
while (len < buflen) {
|
||||
reselect:
|
||||
FD_ZERO(&rfds);
|
||||
FD_SET(fd->ifd, &rfds);
|
||||
|
||||
nfds = select(fd->ifd + 1, &rfds, NULL, NULL, &to2);
|
||||
if (nfds == 0) {
|
||||
avrdude_message(MSG_NOTICE2, "%s: ser_recv(): programmer is not responding\n",
|
||||
progname);
|
||||
return -1;
|
||||
}
|
||||
else if (nfds == -1) {
|
||||
if (errno == EINTR || errno == EAGAIN) {
|
||||
avrdude_message(MSG_INFO, "%s: ser_recv(): programmer is not responding,reselecting\n",
|
||||
progname);
|
||||
goto reselect;
|
||||
}
|
||||
else {
|
||||
avrdude_message(MSG_INFO, "%s: ser_recv(): select(): %s\n",
|
||||
progname, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
rc = read(fd->ifd, p, (buflen - len > 1024) ? 1024 : buflen - len);
|
||||
if (rc < 0) {
|
||||
avrdude_message(MSG_INFO, "%s: ser_recv(): read error: %s\n",
|
||||
progname, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
p += rc;
|
||||
len += rc;
|
||||
}
|
||||
|
||||
p = buf;
|
||||
|
||||
if (verbose > 3)
|
||||
{
|
||||
avrdude_message(MSG_TRACE, "%s: Recv: ", progname);
|
||||
|
||||
while (len) {
|
||||
unsigned char c = *p;
|
||||
if (isprint(c)) {
|
||||
avrdude_message(MSG_TRACE, "%c ", c);
|
||||
}
|
||||
else {
|
||||
avrdude_message(MSG_TRACE, ". ");
|
||||
}
|
||||
avrdude_message(MSG_TRACE, "[%02x] ", c);
|
||||
|
||||
p++;
|
||||
len--;
|
||||
}
|
||||
avrdude_message(MSG_TRACE, "\n");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int ser_drain(union filedescriptor *fd, int display)
|
||||
{
|
||||
struct timeval timeout;
|
||||
fd_set rfds;
|
||||
int nfds;
|
||||
int rc;
|
||||
unsigned char buf;
|
||||
|
||||
timeout.tv_sec = 0;
|
||||
timeout.tv_usec = 250000;
|
||||
|
||||
if (display) {
|
||||
avrdude_message(MSG_INFO, "drain>");
|
||||
}
|
||||
|
||||
while (1) {
|
||||
FD_ZERO(&rfds);
|
||||
FD_SET(fd->ifd, &rfds);
|
||||
|
||||
reselect:
|
||||
nfds = select(fd->ifd + 1, &rfds, NULL, NULL, &timeout);
|
||||
if (nfds == 0) {
|
||||
if (display) {
|
||||
avrdude_message(MSG_INFO, "<drain\n");
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
else if (nfds == -1) {
|
||||
if (errno == EINTR) {
|
||||
goto reselect;
|
||||
}
|
||||
else {
|
||||
avrdude_message(MSG_INFO, "%s: ser_drain(): select(): %s\n",
|
||||
progname, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
rc = read(fd->ifd, &buf, 1);
|
||||
if (rc < 0) {
|
||||
avrdude_message(MSG_INFO, "%s: ser_drain(): read error: %s\n",
|
||||
progname, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
if (display) {
|
||||
avrdude_message(MSG_INFO, "%02x ", buf);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct serial_device serial_serdev =
|
||||
{
|
||||
.open = ser_open,
|
||||
.setparams = ser_setparams,
|
||||
.close = ser_close,
|
||||
.send = ser_send,
|
||||
.recv = ser_recv,
|
||||
.drain = ser_drain,
|
||||
.set_dtr_rts = ser_set_dtr_rts,
|
||||
.flags = SERDEV_FL_CANSETSPEED,
|
||||
};
|
||||
|
||||
struct serial_device *serdev = &serial_serdev;
|
||||
|
||||
#endif /* WIN32NATIVE */
|
||||
816
src/ser_win32.c
Normal file
816
src/ser_win32.c
Normal file
@@ -0,0 +1,816 @@
|
||||
/*
|
||||
* avrdude - A Downloader/Uploader for AVR device programmers
|
||||
* Copyright (C) 2003, 2004 Martin J. Thomas <mthomas@rhrk.uni-kl.de>
|
||||
* Copyright (C) 2006 Joerg Wunsch <j@uriah.heep.sax.de>
|
||||
*
|
||||
* 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/* $Id$ */
|
||||
|
||||
/*
|
||||
* Native Win32 serial interface for avrdude.
|
||||
*/
|
||||
|
||||
#include "ac_cfg.h"
|
||||
|
||||
#if defined(WIN32NATIVE)
|
||||
|
||||
#ifdef HAVE_LIBWS2_32
|
||||
/* winsock2.h must be included before windows.h from avrdude.h... */
|
||||
# include <winsock2.h>
|
||||
#endif
|
||||
|
||||
#include <windows.h>
|
||||
#include <stdio.h>
|
||||
#include <ctype.h> /* for isprint */
|
||||
#include <errno.h> /* ENOTTY */
|
||||
|
||||
#include "avrdude.h"
|
||||
#include "libavrdude.h"
|
||||
|
||||
long serial_recv_timeout = 5000; /* ms */
|
||||
|
||||
#define W32SERBUFSIZE 1024
|
||||
|
||||
struct baud_mapping {
|
||||
long baud;
|
||||
DWORD speed;
|
||||
};
|
||||
|
||||
static unsigned char serial_over_ethernet = 0;
|
||||
|
||||
/* HANDLE hComPort=INVALID_HANDLE_VALUE; */
|
||||
|
||||
static struct baud_mapping baud_lookup_table [] = {
|
||||
{ 300, CBR_300 },
|
||||
{ 600, CBR_600 },
|
||||
{ 1200, CBR_1200 },
|
||||
{ 2400, CBR_2400 },
|
||||
{ 4800, CBR_4800 },
|
||||
{ 9600, CBR_9600 },
|
||||
{ 19200, CBR_19200 },
|
||||
{ 38400, CBR_38400 },
|
||||
{ 57600, CBR_57600 },
|
||||
{ 115200, CBR_115200 },
|
||||
{ 0, 0 } /* Terminator. */
|
||||
};
|
||||
|
||||
static DWORD serial_baud_lookup(long baud)
|
||||
{
|
||||
struct baud_mapping *map = baud_lookup_table;
|
||||
|
||||
while (map->baud) {
|
||||
if (map->baud == baud)
|
||||
return map->speed;
|
||||
map++;
|
||||
}
|
||||
|
||||
/*
|
||||
* If a non-standard BAUD rate is used, issue
|
||||
* a warning (if we are verbose) and return the raw rate
|
||||
*/
|
||||
avrdude_message(MSG_NOTICE, "%s: serial_baud_lookup(): Using non-standard baud rate: %ld",
|
||||
progname, baud);
|
||||
|
||||
return baud;
|
||||
}
|
||||
|
||||
|
||||
static BOOL serial_w32SetTimeOut(HANDLE hComPort, DWORD timeout) // in ms
|
||||
{
|
||||
COMMTIMEOUTS ctmo;
|
||||
ZeroMemory (&ctmo, sizeof(COMMTIMEOUTS));
|
||||
ctmo.ReadIntervalTimeout = timeout;
|
||||
ctmo.ReadTotalTimeoutMultiplier = timeout;
|
||||
ctmo.ReadTotalTimeoutConstant = timeout;
|
||||
|
||||
return SetCommTimeouts(hComPort, &ctmo);
|
||||
}
|
||||
|
||||
static int ser_setparams(union filedescriptor *fd, long baud, unsigned long cflags)
|
||||
{
|
||||
if (serial_over_ethernet) {
|
||||
return -ENOTTY;
|
||||
} else {
|
||||
DCB dcb;
|
||||
HANDLE hComPort = (HANDLE)fd->pfd;
|
||||
|
||||
ZeroMemory (&dcb, sizeof(DCB));
|
||||
dcb.DCBlength = sizeof(DCB);
|
||||
dcb.BaudRate = serial_baud_lookup (baud);
|
||||
dcb.fBinary = 1;
|
||||
dcb.fDtrControl = DTR_CONTROL_DISABLE;
|
||||
dcb.fRtsControl = RTS_CONTROL_DISABLE;
|
||||
switch ((cflags & (SERIAL_CS5 | SERIAL_CS6 | SERIAL_CS7 | SERIAL_CS8))) {
|
||||
case SERIAL_CS5:
|
||||
dcb.ByteSize = 5;
|
||||
break;
|
||||
case SERIAL_CS6:
|
||||
dcb.ByteSize = 6;
|
||||
break;
|
||||
case SERIAL_CS7:
|
||||
dcb.ByteSize = 7;
|
||||
break;
|
||||
case SERIAL_CS8:
|
||||
dcb.ByteSize = 8;
|
||||
break;
|
||||
}
|
||||
switch ((cflags & (SERIAL_NO_PARITY | SERIAL_PARENB | SERIAL_PARODD))) {
|
||||
case SERIAL_NO_PARITY:
|
||||
dcb.Parity = NOPARITY;
|
||||
break;
|
||||
case SERIAL_PARENB:
|
||||
dcb.Parity = EVENPARITY;
|
||||
break;
|
||||
case SERIAL_PARODD:
|
||||
dcb.Parity = ODDPARITY;
|
||||
break;
|
||||
}
|
||||
switch ((cflags & (SERIAL_NO_CSTOPB | SERIAL_CSTOPB))) {
|
||||
case SERIAL_NO_CSTOPB:
|
||||
dcb.StopBits = ONESTOPBIT;
|
||||
break;
|
||||
case SERIAL_CSTOPB:
|
||||
dcb.StopBits = TWOSTOPBITS;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!SetCommState(hComPort, &dcb))
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef HAVE_LIBWS2_32
|
||||
static int
|
||||
net_open(const char *port, union filedescriptor *fdp)
|
||||
{
|
||||
WSADATA wsaData;
|
||||
LPVOID lpMsgBuf;
|
||||
|
||||
char *hstr, *pstr, *end;
|
||||
unsigned int pnum;
|
||||
int fd;
|
||||
struct sockaddr_in sockaddr;
|
||||
struct hostent *hp;
|
||||
|
||||
if (WSAStartup(MAKEWORD(2, 0), &wsaData) != 0) {
|
||||
avrdude_message(MSG_INFO, "%s: net_open(): WSAStartup() failed\n", progname);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ((hstr = strdup(port)) == NULL) {
|
||||
avrdude_message(MSG_INFO, "%s: net_open(): Out of memory!\n", progname);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (((pstr = strchr(hstr, ':')) == NULL) || (pstr == hstr)) {
|
||||
avrdude_message(MSG_INFO, "%s: net_open(): Mangled host:port string \"%s\"\n", progname, hstr);
|
||||
free(hstr);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Terminate the host section of the description.
|
||||
*/
|
||||
*pstr++ = '\0';
|
||||
|
||||
pnum = strtoul(pstr, &end, 10);
|
||||
|
||||
if ((*pstr == '\0') || (*end != '\0') || (pnum == 0) || (pnum > 65535)) {
|
||||
avrdude_message(MSG_INFO, "%s: net_open(): Bad port number \"%s\"\n", progname, pstr);
|
||||
free(hstr);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ((hp = gethostbyname(hstr)) == NULL) {
|
||||
avrdude_message(MSG_INFO, "%s: net_open(): unknown host \"%s\"\n", progname, hstr);
|
||||
free(hstr);
|
||||
return -1;
|
||||
}
|
||||
|
||||
free(hstr);
|
||||
|
||||
if ((fd = socket(PF_INET, SOCK_STREAM, 0)) < 0) {
|
||||
FormatMessage(
|
||||
FORMAT_MESSAGE_ALLOCATE_BUFFER |
|
||||
FORMAT_MESSAGE_FROM_SYSTEM |
|
||||
FORMAT_MESSAGE_IGNORE_INSERTS,
|
||||
NULL,
|
||||
WSAGetLastError(),
|
||||
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
|
||||
(LPTSTR)&lpMsgBuf,
|
||||
0,
|
||||
NULL);
|
||||
avrdude_message(MSG_INFO, "%s: net_open(): Cannot open socket: %s\n", progname, (char *)lpMsgBuf);
|
||||
LocalFree(lpMsgBuf);
|
||||
return -1;
|
||||
}
|
||||
|
||||
memset(&sockaddr, 0, sizeof(struct sockaddr_in));
|
||||
sockaddr.sin_family = AF_INET;
|
||||
sockaddr.sin_port = htons(pnum);
|
||||
memcpy(&(sockaddr.sin_addr.s_addr), hp->h_addr, sizeof(struct in_addr));
|
||||
|
||||
if (connect(fd, (struct sockaddr *)&sockaddr, sizeof(sockaddr))) {
|
||||
FormatMessage(
|
||||
FORMAT_MESSAGE_ALLOCATE_BUFFER |
|
||||
FORMAT_MESSAGE_FROM_SYSTEM |
|
||||
FORMAT_MESSAGE_IGNORE_INSERTS,
|
||||
NULL,
|
||||
WSAGetLastError(),
|
||||
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
|
||||
(LPTSTR)&lpMsgBuf,
|
||||
0,
|
||||
NULL);
|
||||
avrdude_message(MSG_INFO, "%s: net_open(): Connect failed: %s\n", progname, (char *)lpMsgBuf);
|
||||
LocalFree(lpMsgBuf);
|
||||
return -1;
|
||||
}
|
||||
|
||||
fdp->ifd = fd;
|
||||
|
||||
serial_over_ethernet = 1;
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
static int ser_open(char * port, union pinfo pinfo, union filedescriptor *fdp)
|
||||
{
|
||||
LPVOID lpMsgBuf;
|
||||
HANDLE hComPort=INVALID_HANDLE_VALUE;
|
||||
char *newname = 0;
|
||||
|
||||
/*
|
||||
* If the port is of the form "net:<host>:<port>", then
|
||||
* handle it as a TCP connection to a terminal server.
|
||||
*/
|
||||
if (strncmp(port, "net:", strlen("net:")) == 0) {
|
||||
#ifdef HAVE_LIBWS2_32
|
||||
return net_open(port + strlen("net:"), fdp);
|
||||
#else
|
||||
avrdude_message(MSG_INFO, "%s: ser_open(): "
|
||||
"not configured for TCP connections\n",
|
||||
progname);
|
||||
return -1;
|
||||
#endif
|
||||
}
|
||||
|
||||
if (strncasecmp(port, "com", strlen("com")) == 0) {
|
||||
|
||||
// prepend "\\\\.\\" to name, required for port # >= 10
|
||||
newname = malloc(strlen("\\\\.\\") + strlen(port) + 1);
|
||||
|
||||
if (newname == 0) {
|
||||
avrdude_message(MSG_INFO, "%s: ser_open(): out of memory\n",
|
||||
progname);
|
||||
exit(1);
|
||||
}
|
||||
strcpy(newname, "\\\\.\\");
|
||||
strcat(newname, port);
|
||||
|
||||
port = newname;
|
||||
}
|
||||
|
||||
hComPort = CreateFile(port, GENERIC_READ | GENERIC_WRITE, 0, NULL,
|
||||
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
|
||||
|
||||
if (hComPort == INVALID_HANDLE_VALUE) {
|
||||
FormatMessage(
|
||||
FORMAT_MESSAGE_ALLOCATE_BUFFER |
|
||||
FORMAT_MESSAGE_FROM_SYSTEM |
|
||||
FORMAT_MESSAGE_IGNORE_INSERTS,
|
||||
NULL,
|
||||
GetLastError(),
|
||||
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
|
||||
(LPTSTR) &lpMsgBuf,
|
||||
0,
|
||||
NULL);
|
||||
avrdude_message(MSG_INFO, "%s: ser_open(): can't open device \"%s\": %s\n",
|
||||
progname, port, (char*)lpMsgBuf);
|
||||
LocalFree( lpMsgBuf );
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!SetupComm(hComPort, W32SERBUFSIZE, W32SERBUFSIZE))
|
||||
{
|
||||
CloseHandle(hComPort);
|
||||
avrdude_message(MSG_INFO, "%s: ser_open(): can't set buffers for \"%s\"\n",
|
||||
progname, port);
|
||||
return -1;
|
||||
}
|
||||
|
||||
fdp->pfd = (void *)hComPort;
|
||||
if (ser_setparams(fdp, pinfo.serialinfo.baud, pinfo.serialinfo.cflags) != 0)
|
||||
{
|
||||
CloseHandle(hComPort);
|
||||
avrdude_message(MSG_INFO, "%s: ser_open(): can't set com-state for \"%s\"\n",
|
||||
progname, port);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!serial_w32SetTimeOut(hComPort,0))
|
||||
{
|
||||
CloseHandle(hComPort);
|
||||
avrdude_message(MSG_INFO, "%s: ser_open(): can't set initial timeout for \"%s\"\n",
|
||||
progname, port);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (newname != 0) {
|
||||
free(newname);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static void ser_close(union filedescriptor *fd)
|
||||
{
|
||||
if (serial_over_ethernet) {
|
||||
closesocket(fd->ifd);
|
||||
WSACleanup();
|
||||
} else {
|
||||
HANDLE hComPort=(HANDLE)fd->pfd;
|
||||
if (hComPort != INVALID_HANDLE_VALUE)
|
||||
CloseHandle (hComPort);
|
||||
|
||||
hComPort = INVALID_HANDLE_VALUE;
|
||||
}
|
||||
}
|
||||
|
||||
static int ser_set_dtr_rts(union filedescriptor *fd, int is_on)
|
||||
{
|
||||
if (serial_over_ethernet) {
|
||||
return 0;
|
||||
} else {
|
||||
HANDLE hComPort=(HANDLE)fd->pfd;
|
||||
|
||||
if (is_on) {
|
||||
EscapeCommFunction(hComPort, SETDTR);
|
||||
EscapeCommFunction(hComPort, SETRTS);
|
||||
} else {
|
||||
EscapeCommFunction(hComPort, CLRDTR);
|
||||
EscapeCommFunction(hComPort, CLRRTS);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef HAVE_LIBWS2_32
|
||||
static int net_send(union filedescriptor *fd, const unsigned char * buf, size_t buflen)
|
||||
{
|
||||
LPVOID lpMsgBuf;
|
||||
int rc;
|
||||
const unsigned char *p = buf;
|
||||
size_t len = buflen;
|
||||
|
||||
if (fd->ifd < 0) {
|
||||
avrdude_message(MSG_NOTICE, "%s: net_send(): connection not open\n", progname);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (!len) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (verbose > 3) {
|
||||
avrdude_message(MSG_TRACE, "%s: Send: ", progname);
|
||||
|
||||
while (buflen) {
|
||||
unsigned char c = *buf;
|
||||
if (isprint(c)) {
|
||||
avrdude_message(MSG_TRACE, "%c ", c);
|
||||
} else {
|
||||
avrdude_message(MSG_TRACE, ". ");
|
||||
}
|
||||
avrdude_message(MSG_TRACE, "[%02x] ", c);
|
||||
|
||||
buf++;
|
||||
buflen--;
|
||||
}
|
||||
|
||||
avrdude_message(MSG_TRACE, "\n");
|
||||
}
|
||||
|
||||
while (len) {
|
||||
rc = send(fd->ifd, p, (len > 1024) ? 1024 : len, 0);
|
||||
if (rc < 0) {
|
||||
FormatMessage(
|
||||
FORMAT_MESSAGE_ALLOCATE_BUFFER |
|
||||
FORMAT_MESSAGE_FROM_SYSTEM |
|
||||
FORMAT_MESSAGE_IGNORE_INSERTS,
|
||||
NULL,
|
||||
WSAGetLastError(),
|
||||
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
|
||||
(LPTSTR)&lpMsgBuf,
|
||||
0,
|
||||
NULL);
|
||||
avrdude_message(MSG_INFO, "%s: net_send(): send error: %s\n", progname, (char *)lpMsgBuf);
|
||||
LocalFree(lpMsgBuf);
|
||||
exit(1);
|
||||
}
|
||||
p += rc;
|
||||
len -= rc;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
static int ser_send(union filedescriptor *fd, const unsigned char * buf, size_t buflen)
|
||||
{
|
||||
#ifdef HAVE_LIBWS2_32
|
||||
if (serial_over_ethernet) {
|
||||
return net_send(fd, buf, buflen);
|
||||
}
|
||||
#endif
|
||||
|
||||
size_t len = buflen;
|
||||
unsigned char c='\0';
|
||||
DWORD written;
|
||||
const unsigned char * b = buf;
|
||||
|
||||
HANDLE hComPort=(HANDLE)fd->pfd;
|
||||
|
||||
if (hComPort == INVALID_HANDLE_VALUE) {
|
||||
avrdude_message(MSG_INFO, "%s: ser_send(): port not open\n",
|
||||
progname);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!len)
|
||||
return 0;
|
||||
|
||||
if (verbose > 3)
|
||||
{
|
||||
avrdude_message(MSG_TRACE, "%s: Send: ", progname);
|
||||
|
||||
while (len) {
|
||||
c = *b;
|
||||
if (isprint(c)) {
|
||||
avrdude_message(MSG_TRACE, "%c ", c);
|
||||
}
|
||||
else {
|
||||
avrdude_message(MSG_TRACE, ". ");
|
||||
}
|
||||
avrdude_message(MSG_TRACE, "[%02x] ", c);
|
||||
b++;
|
||||
len--;
|
||||
}
|
||||
avrdude_message(MSG_INFO, "\n");
|
||||
}
|
||||
|
||||
serial_w32SetTimeOut(hComPort,500);
|
||||
|
||||
if (!WriteFile (hComPort, buf, buflen, &written, NULL)) {
|
||||
avrdude_message(MSG_INFO, "%s: ser_send(): write error: %s\n",
|
||||
progname, "sorry no info avail"); // TODO
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (written != buflen) {
|
||||
avrdude_message(MSG_INFO, "%s: ser_send(): size/send mismatch\n",
|
||||
progname);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
#ifdef HAVE_LIBWS2_32
|
||||
static int net_recv(union filedescriptor *fd, unsigned char * buf, size_t buflen)
|
||||
{
|
||||
LPVOID lpMsgBuf;
|
||||
struct timeval timeout, to2;
|
||||
fd_set rfds;
|
||||
int nfds;
|
||||
int rc;
|
||||
unsigned char *p = buf;
|
||||
size_t len = 0;
|
||||
|
||||
if (fd->ifd < 0) {
|
||||
avrdude_message(MSG_INFO, "%s: net_recv(): connection not open\n", progname);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
timeout.tv_sec = serial_recv_timeout / 1000L;
|
||||
timeout.tv_usec = (serial_recv_timeout % 1000L) * 1000;
|
||||
to2 = timeout;
|
||||
|
||||
while (len < buflen) {
|
||||
reselect:
|
||||
FD_ZERO(&rfds);
|
||||
FD_SET(fd->ifd, &rfds);
|
||||
|
||||
nfds = select(fd->ifd + 1, &rfds, NULL, NULL, &to2);
|
||||
if (nfds == 0) {
|
||||
if (verbose > 1) {
|
||||
avrdude_message(MSG_NOTICE, "%s: ser_recv(): programmer is not responding\n", progname);
|
||||
}
|
||||
return -1;
|
||||
} else if (nfds == -1) {
|
||||
if (WSAGetLastError() == WSAEINTR || WSAGetLastError() == WSAEINPROGRESS) {
|
||||
avrdude_message(MSG_NOTICE, "%s: ser_recv(): programmer is not responding, reselecting\n", progname);
|
||||
goto reselect;
|
||||
} else {
|
||||
FormatMessage(
|
||||
FORMAT_MESSAGE_ALLOCATE_BUFFER |
|
||||
FORMAT_MESSAGE_FROM_SYSTEM |
|
||||
FORMAT_MESSAGE_IGNORE_INSERTS,
|
||||
NULL,
|
||||
WSAGetLastError(),
|
||||
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
|
||||
(LPTSTR)&lpMsgBuf,
|
||||
0,
|
||||
NULL);
|
||||
avrdude_message(MSG_INFO, "%s: ser_recv(): select(): %s\n", progname, (char *)lpMsgBuf);
|
||||
LocalFree(lpMsgBuf);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
rc = recv(fd->ifd, p, (buflen - len > 1024) ? 1024 : buflen - len, 0);
|
||||
if (rc < 0) {
|
||||
FormatMessage(
|
||||
FORMAT_MESSAGE_ALLOCATE_BUFFER |
|
||||
FORMAT_MESSAGE_FROM_SYSTEM |
|
||||
FORMAT_MESSAGE_IGNORE_INSERTS,
|
||||
NULL,
|
||||
WSAGetLastError(),
|
||||
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
|
||||
(LPTSTR)&lpMsgBuf,
|
||||
0,
|
||||
NULL);
|
||||
avrdude_message(MSG_INFO, "%s: ser_recv(): read error: %s\n", progname, (char *)lpMsgBuf);
|
||||
LocalFree(lpMsgBuf);
|
||||
exit(1);
|
||||
}
|
||||
p += rc;
|
||||
len += rc;
|
||||
}
|
||||
|
||||
p = buf;
|
||||
|
||||
if (verbose > 3) {
|
||||
avrdude_message(MSG_TRACE, "%s: Recv: ", progname);
|
||||
|
||||
while (len) {
|
||||
unsigned char c = *p;
|
||||
if (isprint(c)) {
|
||||
avrdude_message(MSG_TRACE, "%c ", c);
|
||||
} else {
|
||||
avrdude_message(MSG_TRACE, ". ");
|
||||
}
|
||||
avrdude_message(MSG_TRACE, "[%02x] ", c);
|
||||
|
||||
p++;
|
||||
len--;
|
||||
}
|
||||
avrdude_message(MSG_TRACE, "\n");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int ser_recv(union filedescriptor *fd, unsigned char * buf, size_t buflen)
|
||||
{
|
||||
#ifdef HAVE_LIBWS2_32
|
||||
if (serial_over_ethernet) {
|
||||
return net_recv(fd, buf, buflen);
|
||||
}
|
||||
#endif
|
||||
|
||||
unsigned char c;
|
||||
unsigned char * p = buf;
|
||||
DWORD read;
|
||||
|
||||
HANDLE hComPort=(HANDLE)fd->pfd;
|
||||
|
||||
if (hComPort == INVALID_HANDLE_VALUE) {
|
||||
avrdude_message(MSG_INFO, "%s: ser_read(): port not open\n",
|
||||
progname);
|
||||
return -1;
|
||||
}
|
||||
|
||||
serial_w32SetTimeOut(hComPort, serial_recv_timeout);
|
||||
|
||||
if (!ReadFile(hComPort, buf, buflen, &read, NULL)) {
|
||||
LPVOID lpMsgBuf;
|
||||
FormatMessage(
|
||||
FORMAT_MESSAGE_ALLOCATE_BUFFER |
|
||||
FORMAT_MESSAGE_FROM_SYSTEM |
|
||||
FORMAT_MESSAGE_IGNORE_INSERTS,
|
||||
NULL,
|
||||
GetLastError(),
|
||||
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
|
||||
(LPTSTR) &lpMsgBuf,
|
||||
0,
|
||||
NULL );
|
||||
avrdude_message(MSG_INFO, "%s: ser_recv(): read error: %s\n",
|
||||
progname, (char*)lpMsgBuf);
|
||||
LocalFree( lpMsgBuf );
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* time out detected */
|
||||
if (read == 0) {
|
||||
avrdude_message(MSG_NOTICE2, "%s: ser_recv(): programmer is not responding\n",
|
||||
progname);
|
||||
return -1;
|
||||
}
|
||||
|
||||
p = buf;
|
||||
|
||||
if (verbose > 3)
|
||||
{
|
||||
avrdude_message(MSG_TRACE, "%s: Recv: ", progname);
|
||||
|
||||
while (read) {
|
||||
c = *p;
|
||||
if (isprint(c)) {
|
||||
avrdude_message(MSG_TRACE, "%c ", c);
|
||||
}
|
||||
else {
|
||||
avrdude_message(MSG_TRACE, ". ");
|
||||
}
|
||||
avrdude_message(MSG_TRACE, "[%02x] ", c);
|
||||
|
||||
p++;
|
||||
read--;
|
||||
}
|
||||
avrdude_message(MSG_INFO, "\n");
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef HAVE_LIBWS2_32
|
||||
static int net_drain(union filedescriptor *fd, int display)
|
||||
{
|
||||
LPVOID lpMsgBuf;
|
||||
struct timeval timeout;
|
||||
fd_set rfds;
|
||||
int nfds;
|
||||
unsigned char buf;
|
||||
int rc;
|
||||
|
||||
if (fd->ifd < 0) {
|
||||
avrdude_message(MSG_INFO, "%s: ser_drain(): connection not open\n", progname);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (display) {
|
||||
avrdude_message(MSG_INFO, "drain>");
|
||||
}
|
||||
|
||||
timeout.tv_sec = 0;
|
||||
timeout.tv_usec = 250000;
|
||||
|
||||
while (1) {
|
||||
FD_ZERO(&rfds);
|
||||
FD_SET(fd->ifd, &rfds);
|
||||
|
||||
reselect:
|
||||
nfds = select(fd->ifd + 1, &rfds, NULL, NULL, &timeout);
|
||||
if (nfds == 0) {
|
||||
if (display) {
|
||||
avrdude_message(MSG_INFO, "<drain\n");
|
||||
}
|
||||
break;
|
||||
}
|
||||
else if (nfds == -1) {
|
||||
if (WSAGetLastError() == WSAEINTR || WSAGetLastError() == WSAEINPROGRESS) {
|
||||
avrdude_message(MSG_NOTICE, "%s: ser_drain(): programmer is not responding, reselecting\n", progname);
|
||||
goto reselect;
|
||||
} else {
|
||||
FormatMessage(
|
||||
FORMAT_MESSAGE_ALLOCATE_BUFFER |
|
||||
FORMAT_MESSAGE_FROM_SYSTEM |
|
||||
FORMAT_MESSAGE_IGNORE_INSERTS,
|
||||
NULL,
|
||||
WSAGetLastError(),
|
||||
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
|
||||
(LPTSTR)&lpMsgBuf,
|
||||
0,
|
||||
NULL);
|
||||
avrdude_message(MSG_INFO, "%s: ser_drain(): select(): %s\n", progname, (char *)lpMsgBuf);
|
||||
LocalFree(lpMsgBuf);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
rc = recv(fd->ifd, &buf, 1, 0);
|
||||
if (rc < 0) {
|
||||
FormatMessage(
|
||||
FORMAT_MESSAGE_ALLOCATE_BUFFER |
|
||||
FORMAT_MESSAGE_FROM_SYSTEM |
|
||||
FORMAT_MESSAGE_IGNORE_INSERTS,
|
||||
NULL,
|
||||
WSAGetLastError(),
|
||||
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
|
||||
(LPTSTR)&lpMsgBuf,
|
||||
0,
|
||||
NULL);
|
||||
avrdude_message(MSG_INFO, "%s: ser_drain(): read error: %s\n", progname, (char *)lpMsgBuf);
|
||||
LocalFree(lpMsgBuf);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (display) {
|
||||
avrdude_message(MSG_INFO, "%02x ", buf);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int ser_drain(union filedescriptor *fd, int display)
|
||||
{
|
||||
#ifdef HAVE_LIBWS2_32
|
||||
if (serial_over_ethernet) {
|
||||
return net_drain(fd, display);
|
||||
}
|
||||
#endif
|
||||
|
||||
// int rc;
|
||||
unsigned char buf[10];
|
||||
BOOL readres;
|
||||
DWORD read;
|
||||
|
||||
HANDLE hComPort=(HANDLE)fd->pfd;
|
||||
|
||||
if (hComPort == INVALID_HANDLE_VALUE) {
|
||||
avrdude_message(MSG_INFO, "%s: ser_drain(): port not open\n",
|
||||
progname);
|
||||
return -1;
|
||||
}
|
||||
|
||||
serial_w32SetTimeOut(hComPort,250);
|
||||
|
||||
if (display) {
|
||||
avrdude_message(MSG_INFO, "drain>");
|
||||
}
|
||||
|
||||
while (1) {
|
||||
readres=ReadFile(hComPort, buf, 1, &read, NULL);
|
||||
if (!readres) {
|
||||
LPVOID lpMsgBuf;
|
||||
FormatMessage(
|
||||
FORMAT_MESSAGE_ALLOCATE_BUFFER |
|
||||
FORMAT_MESSAGE_FROM_SYSTEM |
|
||||
FORMAT_MESSAGE_IGNORE_INSERTS,
|
||||
NULL,
|
||||
GetLastError(),
|
||||
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
|
||||
(LPTSTR) &lpMsgBuf,
|
||||
0,
|
||||
NULL );
|
||||
avrdude_message(MSG_INFO, "%s: ser_drain(): read error: %s\n",
|
||||
progname, (char*)lpMsgBuf);
|
||||
LocalFree( lpMsgBuf );
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (read) { // data avail
|
||||
if (display) avrdude_message(MSG_INFO, "%02x ", buf[0]);
|
||||
}
|
||||
else { // no more data
|
||||
if (display) avrdude_message(MSG_INFO, "<drain\n");
|
||||
break;
|
||||
}
|
||||
} // while
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct serial_device serial_serdev =
|
||||
{
|
||||
.open = ser_open,
|
||||
.setparams = ser_setparams,
|
||||
.close = ser_close,
|
||||
.send = ser_send,
|
||||
.recv = ser_recv,
|
||||
.drain = ser_drain,
|
||||
.set_dtr_rts = ser_set_dtr_rts,
|
||||
.flags = SERDEV_FL_CANSETSPEED,
|
||||
};
|
||||
|
||||
struct serial_device *serdev = &serial_serdev;
|
||||
|
||||
#endif /* WIN32NATIVE */
|
||||
37
src/serbb.h
Normal file
37
src/serbb.h
Normal file
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* avrdude - A Downloader/Uploader for AVR device programmers
|
||||
* Copyright (C) 2000, 2001, 2002, 2003 Brian S. Dean <bsd@bsdhome.com>
|
||||
* Copyright (C) 2005 Juliane Holzt <avrdude@juliane.holzt.de>
|
||||
*
|
||||
* 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
/* $Id$ */
|
||||
|
||||
#ifndef serbb_h
|
||||
#define serbb_h
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
extern const char serbb_desc[];
|
||||
void serbb_initpgm (PROGRAMMER * pgm);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
321
src/serbb_posix.c
Normal file
321
src/serbb_posix.c
Normal file
@@ -0,0 +1,321 @@
|
||||
/*
|
||||
* avrdude - A Downloader/Uploader for AVR device programmers
|
||||
* Copyright (C) 2000, 2001, 2002, 2003 Brian S. Dean <bsd@bsdhome.com>
|
||||
* Copyright (C) 2005 Juliane Holzt <avrdude@juliane.holzt.de>
|
||||
* Copyright (C) 2006 Joerg Wunsch <j@uriah.heep.sax.de>
|
||||
*
|
||||
* 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
/* $Id$ */
|
||||
|
||||
/*
|
||||
* Posix serial bitbanging interface for avrdude.
|
||||
*/
|
||||
|
||||
#if !defined(WIN32NATIVE)
|
||||
|
||||
#include "ac_cfg.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <termios.h>
|
||||
|
||||
#include "avrdude.h"
|
||||
#include "libavrdude.h"
|
||||
|
||||
#include "bitbang.h"
|
||||
#include "serbb.h"
|
||||
|
||||
#undef DEBUG
|
||||
|
||||
static struct termios oldmode;
|
||||
|
||||
/*
|
||||
serial port/pin mapping
|
||||
|
||||
1 cd <-
|
||||
2 (rxd) <-
|
||||
3 txd ->
|
||||
4 dtr ->
|
||||
5 GND
|
||||
6 dsr <-
|
||||
7 rts ->
|
||||
8 cts <-
|
||||
9 ri <-
|
||||
*/
|
||||
|
||||
#define DB9PINS 9
|
||||
|
||||
static int serregbits[DB9PINS + 1] =
|
||||
{ 0, TIOCM_CD, 0, 0, TIOCM_DTR, 0, TIOCM_DSR, TIOCM_RTS, TIOCM_CTS, TIOCM_RI };
|
||||
|
||||
#ifdef DEBUG
|
||||
static char *serpins[DB9PINS + 1] =
|
||||
{ "NONE", "CD", "RXD", "TXD", "DTR", "GND", "DSR", "RTS", "CTS", "RI" };
|
||||
#endif
|
||||
|
||||
static int serbb_setpin(PROGRAMMER * pgm, int pinfunc, int value)
|
||||
{
|
||||
unsigned int ctl;
|
||||
int r;
|
||||
int pin = pgm->pinno[pinfunc]; // get its value
|
||||
|
||||
if (pin & PIN_INVERSE)
|
||||
{
|
||||
value = !value;
|
||||
pin &= PIN_MASK;
|
||||
}
|
||||
|
||||
if ( pin < 1 || pin > DB9PINS )
|
||||
return -1;
|
||||
|
||||
#ifdef DEBUG
|
||||
printf("%s to %d\n",serpins[pin],value);
|
||||
#endif
|
||||
|
||||
switch ( pin )
|
||||
{
|
||||
case 3: /* txd */
|
||||
r = ioctl(pgm->fd.ifd, value ? TIOCSBRK : TIOCCBRK, 0);
|
||||
if (r < 0) {
|
||||
perror("ioctl(\"TIOCxBRK\")");
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
|
||||
case 4: /* dtr */
|
||||
case 7: /* rts */
|
||||
r = ioctl(pgm->fd.ifd, TIOCMGET, &ctl);
|
||||
if (r < 0) {
|
||||
perror("ioctl(\"TIOCMGET\")");
|
||||
return -1;
|
||||
}
|
||||
if ( value )
|
||||
ctl |= serregbits[pin];
|
||||
else
|
||||
ctl &= ~(serregbits[pin]);
|
||||
r = ioctl(pgm->fd.ifd, TIOCMSET, &ctl);
|
||||
if (r < 0) {
|
||||
perror("ioctl(\"TIOCMSET\")");
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
|
||||
default: /* impossible */
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (pgm->ispdelay > 1)
|
||||
bitbang_delay(pgm->ispdelay);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int serbb_getpin(PROGRAMMER * pgm, int pinfunc)
|
||||
{
|
||||
unsigned int ctl;
|
||||
unsigned char invert;
|
||||
int r;
|
||||
int pin = pgm->pinno[pinfunc]; // get its value
|
||||
|
||||
if (pin & PIN_INVERSE)
|
||||
{
|
||||
invert = 1;
|
||||
pin &= PIN_MASK;
|
||||
} else
|
||||
invert = 0;
|
||||
|
||||
if ( pin < 1 || pin > DB9PINS )
|
||||
return(-1);
|
||||
|
||||
switch ( pin )
|
||||
{
|
||||
case 2: /* rxd, currently not implemented, FIXME */
|
||||
return(-1);
|
||||
|
||||
case 1: /* cd */
|
||||
case 6: /* dsr */
|
||||
case 8: /* cts */
|
||||
case 9: /* ri */
|
||||
r = ioctl(pgm->fd.ifd, TIOCMGET, &ctl);
|
||||
if (r < 0) {
|
||||
perror("ioctl(\"TIOCMGET\")");
|
||||
return -1;
|
||||
}
|
||||
if ( !invert )
|
||||
{
|
||||
#ifdef DEBUG
|
||||
printf("%s is %d\n",serpins[pin],(ctl & serregbits[pin]) ? 1 : 0 );
|
||||
#endif
|
||||
return ( (ctl & serregbits[pin]) ? 1 : 0 );
|
||||
}
|
||||
else
|
||||
{
|
||||
#ifdef DEBUG
|
||||
printf("%s is %d (~)\n",serpins[pin],(ctl & serregbits[pin]) ? 0 : 1 );
|
||||
#endif
|
||||
return (( ctl & serregbits[pin]) ? 0 : 1 );
|
||||
}
|
||||
|
||||
default: /* impossible */
|
||||
return(-1);
|
||||
}
|
||||
}
|
||||
|
||||
static int serbb_highpulsepin(PROGRAMMER * pgm, int pinfunc)
|
||||
{
|
||||
int pin = pgm->pinno[pinfunc]; // replace pin name by its value
|
||||
|
||||
if ( (pin & PIN_MASK) < 1 || (pin & PIN_MASK) > DB9PINS )
|
||||
return -1;
|
||||
|
||||
serbb_setpin(pgm, pinfunc, 1);
|
||||
serbb_setpin(pgm, pinfunc, 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void serbb_display(PROGRAMMER *pgm, const char *p)
|
||||
{
|
||||
/* MAYBE */
|
||||
}
|
||||
|
||||
static void serbb_enable(PROGRAMMER *pgm)
|
||||
{
|
||||
/* nothing */
|
||||
}
|
||||
|
||||
static void serbb_disable(PROGRAMMER *pgm)
|
||||
{
|
||||
/* nothing */
|
||||
}
|
||||
|
||||
static void serbb_powerup(PROGRAMMER *pgm)
|
||||
{
|
||||
/* nothing */
|
||||
}
|
||||
|
||||
static void serbb_powerdown(PROGRAMMER *pgm)
|
||||
{
|
||||
/* nothing */
|
||||
}
|
||||
|
||||
static int serbb_open(PROGRAMMER *pgm, char *port)
|
||||
{
|
||||
struct termios mode;
|
||||
int flags;
|
||||
int r;
|
||||
|
||||
if (bitbang_check_prerequisites(pgm) < 0)
|
||||
return -1;
|
||||
|
||||
/* adapted from uisp code */
|
||||
|
||||
pgm->fd.ifd = open(port, O_RDWR | O_NOCTTY | O_NONBLOCK);
|
||||
|
||||
if (pgm->fd.ifd < 0) {
|
||||
perror(port);
|
||||
return(-1);
|
||||
}
|
||||
|
||||
r = tcgetattr(pgm->fd.ifd, &mode);
|
||||
if (r < 0) {
|
||||
avrdude_message(MSG_INFO, "%s: ", port);
|
||||
perror("tcgetattr");
|
||||
return(-1);
|
||||
}
|
||||
oldmode = mode;
|
||||
|
||||
mode.c_iflag = IGNBRK | IGNPAR;
|
||||
mode.c_oflag = 0;
|
||||
mode.c_cflag = CLOCAL | CREAD | CS8 | B9600;
|
||||
mode.c_cc [VMIN] = 1;
|
||||
mode.c_cc [VTIME] = 0;
|
||||
|
||||
r = tcsetattr(pgm->fd.ifd, TCSANOW, &mode);
|
||||
if (r < 0) {
|
||||
avrdude_message(MSG_INFO, "%s: ", port);
|
||||
perror("tcsetattr");
|
||||
return(-1);
|
||||
}
|
||||
|
||||
/* Clear O_NONBLOCK flag. */
|
||||
flags = fcntl(pgm->fd.ifd, F_GETFL, 0);
|
||||
if (flags == -1)
|
||||
{
|
||||
avrdude_message(MSG_INFO, "%s: Can not get flags: %s\n",
|
||||
progname, strerror(errno));
|
||||
return(-1);
|
||||
}
|
||||
flags &= ~O_NONBLOCK;
|
||||
if (fcntl(pgm->fd.ifd, F_SETFL, flags) == -1)
|
||||
{
|
||||
avrdude_message(MSG_INFO, "%s: Can not clear nonblock flag: %s\n",
|
||||
progname, strerror(errno));
|
||||
return(-1);
|
||||
}
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
||||
static void serbb_close(PROGRAMMER *pgm)
|
||||
{
|
||||
if (pgm->fd.ifd != -1)
|
||||
{
|
||||
(void)tcsetattr(pgm->fd.ifd, TCSANOW, &oldmode);
|
||||
pgm->setpin(pgm, PIN_AVR_RESET, 1);
|
||||
close(pgm->fd.ifd);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
const char serbb_desc[] = "Serial port bitbanging";
|
||||
|
||||
void serbb_initpgm(PROGRAMMER *pgm)
|
||||
{
|
||||
strcpy(pgm->type, "SERBB");
|
||||
|
||||
pgm_fill_old_pins(pgm); // TODO to be removed if old pin data no longer needed
|
||||
|
||||
pgm->rdy_led = bitbang_rdy_led;
|
||||
pgm->err_led = bitbang_err_led;
|
||||
pgm->pgm_led = bitbang_pgm_led;
|
||||
pgm->vfy_led = bitbang_vfy_led;
|
||||
pgm->initialize = bitbang_initialize;
|
||||
pgm->display = serbb_display;
|
||||
pgm->enable = serbb_enable;
|
||||
pgm->disable = serbb_disable;
|
||||
pgm->powerup = serbb_powerup;
|
||||
pgm->powerdown = serbb_powerdown;
|
||||
pgm->program_enable = bitbang_program_enable;
|
||||
pgm->chip_erase = bitbang_chip_erase;
|
||||
pgm->cmd = bitbang_cmd;
|
||||
pgm->cmd_tpi = bitbang_cmd_tpi;
|
||||
pgm->open = serbb_open;
|
||||
pgm->close = serbb_close;
|
||||
pgm->setpin = serbb_setpin;
|
||||
pgm->getpin = serbb_getpin;
|
||||
pgm->highpulsepin = serbb_highpulsepin;
|
||||
pgm->read_byte = avr_read_byte_default;
|
||||
pgm->write_byte = avr_write_byte_default;
|
||||
}
|
||||
|
||||
#endif /* WIN32NATIVE */
|
||||
366
src/serbb_win32.c
Normal file
366
src/serbb_win32.c
Normal file
@@ -0,0 +1,366 @@
|
||||
/*
|
||||
* avrdude - A Downloader/Uploader for AVR device programmers
|
||||
* Copyright (C) 2003, 2004 Martin J. Thomas <mthomas@rhrk.uni-kl.de>
|
||||
* Copyright (C) 2005 Juliane Holzt <avrdude@juliane.holzt.de>
|
||||
* Copyright (C) 2005, 2006 Joerg Wunsch <j@uriah.heep.sax.de>
|
||||
*
|
||||
* 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
/* $Id$ */
|
||||
|
||||
/*
|
||||
* Win32 serial bitbanging interface for avrdude.
|
||||
*/
|
||||
|
||||
#include "avrdude.h"
|
||||
|
||||
#if defined(WIN32NATIVE)
|
||||
|
||||
|
||||
#include "ac_cfg.h"
|
||||
|
||||
#include <windows.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "avrdude.h"
|
||||
#include "libavrdude.h"
|
||||
|
||||
#include "bitbang.h"
|
||||
#include "serbb.h"
|
||||
|
||||
/* cached status lines */
|
||||
static int dtr, rts, txd;
|
||||
|
||||
#define W32SERBUFSIZE 1024
|
||||
|
||||
/*
|
||||
serial port/pin mapping
|
||||
|
||||
1 cd <-
|
||||
2 (rxd) <-
|
||||
3 txd ->
|
||||
4 dtr ->
|
||||
5 GND
|
||||
6 dsr <-
|
||||
7 rts ->
|
||||
8 cts <-
|
||||
9 ri <-
|
||||
*/
|
||||
|
||||
#define DB9PINS 9
|
||||
|
||||
static int serbb_setpin(PROGRAMMER * pgm, int pinfunc, int value)
|
||||
{
|
||||
int pin = pgm->pinno[pinfunc];
|
||||
HANDLE hComPort = (HANDLE)pgm->fd.pfd;
|
||||
LPVOID lpMsgBuf;
|
||||
DWORD dwFunc;
|
||||
const char *name;
|
||||
|
||||
if (pin & PIN_INVERSE)
|
||||
{
|
||||
value = !value;
|
||||
pin &= PIN_MASK;
|
||||
}
|
||||
|
||||
if (pin < 1 || pin > DB9PINS)
|
||||
return -1;
|
||||
|
||||
switch (pin)
|
||||
{
|
||||
case 3: /* txd */
|
||||
dwFunc = value? SETBREAK: CLRBREAK;
|
||||
name = value? "SETBREAK": "CLRBREAK";
|
||||
txd = value;
|
||||
break;
|
||||
|
||||
case 4: /* dtr */
|
||||
dwFunc = value? SETDTR: CLRDTR;
|
||||
name = value? "SETDTR": "CLRDTR";
|
||||
dtr = value;
|
||||
break;
|
||||
|
||||
case 7: /* rts */
|
||||
dwFunc = value? SETRTS: CLRRTS;
|
||||
name = value? "SETRTS": "CLRRTS";
|
||||
break;
|
||||
|
||||
default:
|
||||
avrdude_message(MSG_NOTICE, "%s: serbb_setpin(): unknown pin %d\n",
|
||||
progname, pin + 1);
|
||||
return -1;
|
||||
}
|
||||
avrdude_message(MSG_TRACE2, "%s: serbb_setpin(): EscapeCommFunction(%s)\n",
|
||||
progname, name);
|
||||
if (!EscapeCommFunction(hComPort, dwFunc))
|
||||
{
|
||||
FormatMessage(
|
||||
FORMAT_MESSAGE_ALLOCATE_BUFFER |
|
||||
FORMAT_MESSAGE_FROM_SYSTEM |
|
||||
FORMAT_MESSAGE_IGNORE_INSERTS,
|
||||
NULL,
|
||||
GetLastError(),
|
||||
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
|
||||
(LPTSTR) &lpMsgBuf,
|
||||
0,
|
||||
NULL);
|
||||
avrdude_message(MSG_INFO, "%s: serbb_setpin(): SetCommState() failed: %s\n",
|
||||
progname, (char *)lpMsgBuf);
|
||||
CloseHandle(hComPort);
|
||||
LocalFree(lpMsgBuf);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (pgm->ispdelay > 1)
|
||||
bitbang_delay(pgm->ispdelay);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int serbb_getpin(PROGRAMMER * pgm, int pinfunc)
|
||||
{
|
||||
int pin = pgm->pinno[pinfunc];
|
||||
HANDLE hComPort = (HANDLE)pgm->fd.pfd;
|
||||
LPVOID lpMsgBuf;
|
||||
int invert, rv;
|
||||
const char *name;
|
||||
DWORD modemstate;
|
||||
|
||||
if (pin & PIN_INVERSE)
|
||||
{
|
||||
invert = 1;
|
||||
pin &= PIN_MASK;
|
||||
} else
|
||||
invert = 0;
|
||||
|
||||
if (pin < 1 || pin > DB9PINS)
|
||||
return -1;
|
||||
|
||||
if (pin == 1 /* cd */ || pin == 6 /* dsr */ || pin == 8 /* cts */)
|
||||
{
|
||||
if (!GetCommModemStatus(hComPort, &modemstate))
|
||||
{
|
||||
FormatMessage(
|
||||
FORMAT_MESSAGE_ALLOCATE_BUFFER |
|
||||
FORMAT_MESSAGE_FROM_SYSTEM |
|
||||
FORMAT_MESSAGE_IGNORE_INSERTS,
|
||||
NULL,
|
||||
GetLastError(),
|
||||
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
|
||||
(LPTSTR) &lpMsgBuf,
|
||||
0,
|
||||
NULL);
|
||||
avrdude_message(MSG_INFO, "%s: serbb_setpin(): GetCommModemStatus() failed: %s\n",
|
||||
progname, (char *)lpMsgBuf);
|
||||
CloseHandle(hComPort);
|
||||
LocalFree(lpMsgBuf);
|
||||
return -1;
|
||||
}
|
||||
avrdude_message(MSG_TRACE2, "%s: serbb_getpin(): GetCommState() => 0x%lx\n",
|
||||
progname, modemstate);
|
||||
switch (pin)
|
||||
{
|
||||
case 1:
|
||||
modemstate &= MS_RLSD_ON;
|
||||
break;
|
||||
case 6:
|
||||
modemstate &= MS_DSR_ON;
|
||||
break;
|
||||
case 8:
|
||||
modemstate &= MS_CTS_ON;
|
||||
break;
|
||||
}
|
||||
rv = modemstate != 0;
|
||||
if (invert)
|
||||
rv = !rv;
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
switch (pin)
|
||||
{
|
||||
case 3: /* txd */
|
||||
rv = txd;
|
||||
name = "TXD";
|
||||
break;
|
||||
case 4: /* dtr */
|
||||
rv = dtr;
|
||||
name = "DTR";
|
||||
break;
|
||||
case 7: /* rts */
|
||||
rv = rts;
|
||||
name = "RTS";
|
||||
break;
|
||||
default:
|
||||
avrdude_message(MSG_NOTICE, "%s: serbb_getpin(): unknown pin %d\n",
|
||||
progname, pin + 1);
|
||||
return -1;
|
||||
}
|
||||
avrdude_message(MSG_TRACE2, "%s: serbb_getpin(): return cached state for %s\n",
|
||||
progname, name);
|
||||
if (invert)
|
||||
rv = !rv;
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
static int serbb_highpulsepin(PROGRAMMER * pgm, int pinfunc)
|
||||
{
|
||||
int pin = pgm->pinno[pinfunc];
|
||||
if ( (pin & PIN_MASK) < 1 || (pin & PIN_MASK) > DB9PINS )
|
||||
return -1;
|
||||
|
||||
serbb_setpin(pgm, pinfunc, 1);
|
||||
serbb_setpin(pgm, pinfunc, 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static void serbb_display(PROGRAMMER *pgm, const char *p)
|
||||
{
|
||||
/* MAYBE */
|
||||
}
|
||||
|
||||
static void serbb_enable(PROGRAMMER *pgm)
|
||||
{
|
||||
/* nothing */
|
||||
}
|
||||
|
||||
static void serbb_disable(PROGRAMMER *pgm)
|
||||
{
|
||||
/* nothing */
|
||||
}
|
||||
|
||||
static void serbb_powerup(PROGRAMMER *pgm)
|
||||
{
|
||||
/* nothing */
|
||||
}
|
||||
|
||||
static void serbb_powerdown(PROGRAMMER *pgm)
|
||||
{
|
||||
/* nothing */
|
||||
}
|
||||
|
||||
static int serbb_open(PROGRAMMER *pgm, char *port)
|
||||
{
|
||||
DCB dcb;
|
||||
LPVOID lpMsgBuf;
|
||||
HANDLE hComPort = INVALID_HANDLE_VALUE;
|
||||
|
||||
if (bitbang_check_prerequisites(pgm) < 0)
|
||||
return -1;
|
||||
|
||||
hComPort = CreateFile(port, GENERIC_READ | GENERIC_WRITE, 0, NULL,
|
||||
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
|
||||
|
||||
if (hComPort == INVALID_HANDLE_VALUE) {
|
||||
FormatMessage(
|
||||
FORMAT_MESSAGE_ALLOCATE_BUFFER |
|
||||
FORMAT_MESSAGE_FROM_SYSTEM |
|
||||
FORMAT_MESSAGE_IGNORE_INSERTS,
|
||||
NULL,
|
||||
GetLastError(),
|
||||
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
|
||||
(LPTSTR) &lpMsgBuf,
|
||||
0,
|
||||
NULL);
|
||||
avrdude_message(MSG_INFO, "%s: ser_open(): can't open device \"%s\": %s\n",
|
||||
progname, port, (char*)lpMsgBuf);
|
||||
LocalFree(lpMsgBuf);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!SetupComm(hComPort, W32SERBUFSIZE, W32SERBUFSIZE))
|
||||
{
|
||||
CloseHandle(hComPort);
|
||||
avrdude_message(MSG_INFO, "%s: ser_open(): can't set buffers for \"%s\"\n",
|
||||
progname, port);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
ZeroMemory(&dcb, sizeof(DCB));
|
||||
dcb.DCBlength = sizeof(DCB);
|
||||
dcb.BaudRate = CBR_9600;
|
||||
dcb.fBinary = 1;
|
||||
dcb.fDtrControl = DTR_CONTROL_DISABLE;
|
||||
dcb.fRtsControl = RTS_CONTROL_DISABLE;
|
||||
dcb.ByteSize = 8;
|
||||
dcb.Parity = NOPARITY;
|
||||
dcb.StopBits = ONESTOPBIT;
|
||||
|
||||
if (!SetCommState(hComPort, &dcb))
|
||||
{
|
||||
CloseHandle(hComPort);
|
||||
avrdude_message(MSG_INFO, "%s: ser_open(): can't set com-state for \"%s\"\n",
|
||||
progname, port);
|
||||
return -1;
|
||||
}
|
||||
avrdude_message(MSG_DEBUG, "%s: ser_open(): opened comm port \"%s\", handle 0x%x\n",
|
||||
progname, port, (int)hComPort);
|
||||
|
||||
pgm->fd.pfd = (void *)hComPort;
|
||||
|
||||
dtr = rts = txd = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void serbb_close(PROGRAMMER *pgm)
|
||||
{
|
||||
HANDLE hComPort=(HANDLE)pgm->fd.pfd;
|
||||
if (hComPort != INVALID_HANDLE_VALUE)
|
||||
{
|
||||
pgm->setpin(pgm, PIN_AVR_RESET, 1);
|
||||
CloseHandle (hComPort);
|
||||
}
|
||||
avrdude_message(MSG_DEBUG, "%s: ser_close(): closed comm port handle 0x%x\n",
|
||||
progname, (int)hComPort);
|
||||
|
||||
hComPort = INVALID_HANDLE_VALUE;
|
||||
}
|
||||
|
||||
const char serbb_desc[] = "Serial port bitbanging";
|
||||
|
||||
void serbb_initpgm(PROGRAMMER *pgm)
|
||||
{
|
||||
strcpy(pgm->type, "SERBB");
|
||||
|
||||
pgm_fill_old_pins(pgm); // TODO to be removed if old pin data no longer needed
|
||||
|
||||
pgm->rdy_led = bitbang_rdy_led;
|
||||
pgm->err_led = bitbang_err_led;
|
||||
pgm->pgm_led = bitbang_pgm_led;
|
||||
pgm->vfy_led = bitbang_vfy_led;
|
||||
pgm->initialize = bitbang_initialize;
|
||||
pgm->display = serbb_display;
|
||||
pgm->enable = serbb_enable;
|
||||
pgm->disable = serbb_disable;
|
||||
pgm->powerup = serbb_powerup;
|
||||
pgm->powerdown = serbb_powerdown;
|
||||
pgm->program_enable = bitbang_program_enable;
|
||||
pgm->chip_erase = bitbang_chip_erase;
|
||||
pgm->cmd = bitbang_cmd;
|
||||
pgm->cmd_tpi = bitbang_cmd_tpi;
|
||||
pgm->open = serbb_open;
|
||||
pgm->close = serbb_close;
|
||||
pgm->setpin = serbb_setpin;
|
||||
pgm->getpin = serbb_getpin;
|
||||
pgm->highpulsepin = serbb_highpulsepin;
|
||||
pgm->read_byte = avr_read_byte_default;
|
||||
pgm->write_byte = avr_write_byte_default;
|
||||
}
|
||||
|
||||
#endif /* WIN32NATIVE */
|
||||
50
src/solaris_ecpp.h
Normal file
50
src/solaris_ecpp.h
Normal file
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* avrdude - A Downloader/Uploader for AVR device programmers
|
||||
* Copyright (C) 2005 Joerg Wunsch
|
||||
*
|
||||
* 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/* $Id$ */
|
||||
|
||||
#ifndef solaris_ecpp_h
|
||||
#define solaris_ecpp_h
|
||||
|
||||
#include <sys/ecppio.h>
|
||||
|
||||
#define ppi_claim(fd) \
|
||||
do { \
|
||||
struct ecpp_transfer_parms p; \
|
||||
(void)ioctl(fd, ECPPIOC_GETPARMS, &p); \
|
||||
p.mode = ECPP_DIAG_MODE; \
|
||||
(void)ioctl(fd, ECPPIOC_SETPARMS, &p); \
|
||||
} while(0);
|
||||
|
||||
#define ppi_release(fd)
|
||||
|
||||
#define DO_PPI_READ(fd, reg, valp) \
|
||||
do { struct ecpp_regs r; \
|
||||
if ((reg) == PPIDATA) { (void)ioctl(fd, ECPPIOC_GETDATA, valp); } \
|
||||
else { (void)ioctl(fd, ECPPIOC_GETREGS, &r); \
|
||||
*(valp) = ((reg) == PPICTRL)? r.dcr: r.dsr; } \
|
||||
} while(0)
|
||||
#define DO_PPI_WRITE(fd, reg, valp) \
|
||||
do { struct ecpp_regs r; \
|
||||
if ((reg) == PPIDATA) { (void)ioctl(fd, ECPPIOC_SETDATA, valp); } \
|
||||
else { if ((reg) == PPICTRL) r.dcr = *(valp); else r.dsr = *(valp); \
|
||||
(void)ioctl(fd, ECPPIOC_SETREGS, &r); } \
|
||||
} while(0)
|
||||
|
||||
|
||||
#endif /* solaris_ecpp_h */
|
||||
1321
src/stk500.c
Normal file
1321
src/stk500.c
Normal file
File diff suppressed because it is too large
Load Diff
41
src/stk500.h
Normal file
41
src/stk500.h
Normal file
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* avrdude - A Downloader/Uploader for AVR device programmers
|
||||
* Copyright (C) 2002-2004 Brian S. Dean <bsd@bsdhome.com>
|
||||
*
|
||||
* 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/* $Id$ */
|
||||
|
||||
#ifndef stk500_h
|
||||
#define stk500_h
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
extern const char stk500_desc[];
|
||||
void stk500_initpgm (PROGRAMMER * pgm);
|
||||
|
||||
/* used by arduino.c to avoid duplicate code */
|
||||
int stk500_getsync(PROGRAMMER * pgm);
|
||||
int stk500_drain(PROGRAMMER * pgm, int display);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
103
src/stk500_private.h
Normal file
103
src/stk500_private.h
Normal file
@@ -0,0 +1,103 @@
|
||||
//**** ATMEL AVR - A P P L I C A T I O N N O T E ************************
|
||||
//*
|
||||
//* Title: AVR061 - STK500 Communication Protocol
|
||||
//* Filename: command.h
|
||||
//* Version: 1.0
|
||||
//* Last updated: 09.09.2002
|
||||
//*
|
||||
//* Support E-mail: avr@atmel.com
|
||||
//*
|
||||
//**************************************************************************
|
||||
|
||||
// *****************[ STK Message constants ]***************************
|
||||
|
||||
#define STK_SIGN_ON_MESSAGE "AVR STK" // Sign on string for Cmnd_STK_GET_SIGN_ON
|
||||
|
||||
// *****************[ STK Response constants ]***************************
|
||||
|
||||
#define Resp_STK_OK 0x10 // ' '
|
||||
#define Resp_STK_FAILED 0x11 // ' '
|
||||
#define Resp_STK_UNKNOWN 0x12 // ' '
|
||||
#define Resp_STK_NODEVICE 0x13 // ' '
|
||||
#define Resp_STK_INSYNC 0x14 // ' '
|
||||
#define Resp_STK_NOSYNC 0x15 // ' '
|
||||
|
||||
#define Resp_ADC_CHANNEL_ERROR 0x16 // ' '
|
||||
#define Resp_ADC_MEASURE_OK 0x17 // ' '
|
||||
#define Resp_PWM_CHANNEL_ERROR 0x18 // ' '
|
||||
#define Resp_PWM_ADJUST_OK 0x19 // ' '
|
||||
|
||||
// *****************[ STK Special constants ]***************************
|
||||
|
||||
#define Sync_CRC_EOP 0x20 // 'SPACE'
|
||||
|
||||
// *****************[ STK Command constants ]***************************
|
||||
|
||||
#define Cmnd_STK_GET_SYNC 0x30 // ' '
|
||||
#define Cmnd_STK_GET_SIGN_ON 0x31 // ' '
|
||||
|
||||
#define Cmnd_STK_SET_PARAMETER 0x40 // ' '
|
||||
#define Cmnd_STK_GET_PARAMETER 0x41 // ' '
|
||||
#define Cmnd_STK_SET_DEVICE 0x42 // ' '
|
||||
#define Cmnd_STK_SET_DEVICE_EXT 0x45 // ' '
|
||||
|
||||
#define Cmnd_STK_ENTER_PROGMODE 0x50 // ' '
|
||||
#define Cmnd_STK_LEAVE_PROGMODE 0x51 // ' '
|
||||
#define Cmnd_STK_CHIP_ERASE 0x52 // ' '
|
||||
#define Cmnd_STK_CHECK_AUTOINC 0x53 // ' '
|
||||
#define Cmnd_STK_LOAD_ADDRESS 0x55 // ' '
|
||||
#define Cmnd_STK_UNIVERSAL 0x56 // ' '
|
||||
#define Cmnd_STK_UNIVERSAL_MULTI 0x57 // ' '
|
||||
|
||||
#define Cmnd_STK_PROG_FLASH 0x60 // ' '
|
||||
#define Cmnd_STK_PROG_DATA 0x61 // ' '
|
||||
#define Cmnd_STK_PROG_FUSE 0x62 // ' '
|
||||
#define Cmnd_STK_PROG_LOCK 0x63 // ' '
|
||||
#define Cmnd_STK_PROG_PAGE 0x64 // ' '
|
||||
#define Cmnd_STK_PROG_FUSE_EXT 0x65 // ' '
|
||||
|
||||
#define Cmnd_STK_READ_FLASH 0x70 // ' '
|
||||
#define Cmnd_STK_READ_DATA 0x71 // ' '
|
||||
#define Cmnd_STK_READ_FUSE 0x72 // ' '
|
||||
#define Cmnd_STK_READ_LOCK 0x73 // ' '
|
||||
#define Cmnd_STK_READ_PAGE 0x74 // ' '
|
||||
#define Cmnd_STK_READ_SIGN 0x75 // ' '
|
||||
#define Cmnd_STK_READ_OSCCAL 0x76 // ' '
|
||||
#define Cmnd_STK_READ_FUSE_EXT 0x77 // ' '
|
||||
#define Cmnd_STK_READ_OSCCAL_EXT 0x78 // ' '
|
||||
|
||||
// *****************[ STK Parameter constants ]***************************
|
||||
|
||||
#define Parm_STK_HW_VER 0x80 // ' ' - R
|
||||
#define Parm_STK_SW_MAJOR 0x81 // ' ' - R
|
||||
#define Parm_STK_SW_MINOR 0x82 // ' ' - R
|
||||
#define Parm_STK_LEDS 0x83 // ' ' - R/W
|
||||
#define Parm_STK_VTARGET 0x84 // ' ' - R/W
|
||||
#define Parm_STK_VADJUST 0x85 // ' ' - R/W
|
||||
#define Parm_STK_OSC_PSCALE 0x86 // ' ' - R/W
|
||||
#define Parm_STK_OSC_CMATCH 0x87 // ' ' - R/W
|
||||
#define Parm_STK_RESET_DURATION 0x88 // ' ' - R/W
|
||||
#define Parm_STK_SCK_DURATION 0x89 // ' ' - R/W
|
||||
|
||||
#define Parm_STK_BUFSIZEL 0x90 // ' ' - R/W, Range {0..255}
|
||||
#define Parm_STK_BUFSIZEH 0x91 // ' ' - R/W, Range {0..255}
|
||||
#define Parm_STK_DEVICE 0x92 // ' ' - R/W, Range {0..255}
|
||||
#define Parm_STK_PROGMODE 0x93 // ' ' - 'P' or 'S'
|
||||
#define Parm_STK_PARAMODE 0x94 // ' ' - TRUE or FALSE
|
||||
#define Parm_STK_POLLING 0x95 // ' ' - TRUE or FALSE
|
||||
#define Parm_STK_SELFTIMED 0x96 // ' ' - TRUE or FALSE
|
||||
#define Param_STK500_TOPCARD_DETECT 0x98 // ' ' - Detect top-card attached
|
||||
|
||||
// *****************[ STK status bit definitions ]***************************
|
||||
|
||||
#define Stat_STK_INSYNC 0x01 // INSYNC status bit, '1' - INSYNC
|
||||
#define Stat_STK_PROGMODE 0x02 // Programming mode, '1' - PROGMODE
|
||||
#define Stat_STK_STANDALONE 0x04 // Standalone mode, '1' - SM mode
|
||||
#define Stat_STK_RESET 0x08 // RESET button, '1' - Pushed
|
||||
#define Stat_STK_PROGRAM 0x10 // Program button, ' 1' - Pushed
|
||||
#define Stat_STK_LEDG 0x20 // Green LED status, '1' - Lit
|
||||
#define Stat_STK_LEDR 0x40 // Red LED status, '1' - Lit
|
||||
#define Stat_STK_LEDBLINK 0x80 // LED blink ON/OFF, '1' - Blink
|
||||
|
||||
|
||||
// *****************************[ End Of COMMAND.H ]**************************
|
||||
90
src/stk500generic.c
Normal file
90
src/stk500generic.c
Normal file
@@ -0,0 +1,90 @@
|
||||
/*
|
||||
* avrdude - A Downloader/Uploader for AVR device programmers
|
||||
* Copyright (C) 2006 Joerg Wunsch <j@uriah.heep.sax.de>
|
||||
*
|
||||
* 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/* $Id$ */
|
||||
|
||||
/*
|
||||
* avrdude interface for Atmel STK500 programmer
|
||||
*
|
||||
* This is a wrapper around the STK500[v1] and STK500v2 programmers.
|
||||
* Try to select the programmer type that actually responds, and
|
||||
* divert to the actual programmer implementation if successful.
|
||||
*/
|
||||
|
||||
#include "ac_cfg.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "avrdude.h"
|
||||
#include "libavrdude.h"
|
||||
|
||||
#include "stk500generic.h"
|
||||
#include "stk500.h"
|
||||
#include "stk500v2.h"
|
||||
|
||||
static int stk500generic_open(PROGRAMMER * pgm, char * port)
|
||||
{
|
||||
stk500_initpgm(pgm);
|
||||
if (pgm->open(pgm, port) >= 0)
|
||||
{
|
||||
avrdude_message(MSG_INFO, "%s: successfully opened stk500v1 device -- please use -c stk500v1\n",
|
||||
progname);
|
||||
return 0;
|
||||
}
|
||||
|
||||
pgm->close(pgm);
|
||||
|
||||
stk500v2_initpgm(pgm);
|
||||
if (pgm->open(pgm, port) >= 0)
|
||||
{
|
||||
avrdude_message(MSG_INFO, "%s: successfully opened stk500v2 device -- please use -c stk500v2\n",
|
||||
progname);
|
||||
return 0;
|
||||
}
|
||||
|
||||
avrdude_message(MSG_INFO, "%s: cannot open either stk500v1 or stk500v2 programmer\n",
|
||||
progname);
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void stk500generic_setup(PROGRAMMER * pgm)
|
||||
{
|
||||
/*
|
||||
* Only STK500v2 needs setup/teardown.
|
||||
*/
|
||||
stk500v2_initpgm(pgm);
|
||||
pgm->setup(pgm);
|
||||
}
|
||||
|
||||
static void stk500generic_teardown(PROGRAMMER * pgm)
|
||||
{
|
||||
stk500v2_initpgm(pgm);
|
||||
pgm->teardown(pgm);
|
||||
}
|
||||
|
||||
const char stk500generic_desc[] = "Atmel STK500, autodetect firmware version";
|
||||
|
||||
void stk500generic_initpgm(PROGRAMMER * pgm)
|
||||
{
|
||||
strcpy(pgm->type, "STK500GENERIC");
|
||||
|
||||
pgm->open = stk500generic_open;
|
||||
pgm->setup = stk500generic_setup;
|
||||
pgm->teardown = stk500generic_teardown;
|
||||
}
|
||||
29
src/stk500generic.h
Normal file
29
src/stk500generic.h
Normal file
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
* avrdude - A Downloader/Uploader for AVR device programmers
|
||||
* Copyright (C) 2006 Joerg Wunsch <j@uriah.heep.sax.de>
|
||||
*
|
||||
* 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/* $Id$ */
|
||||
|
||||
#ifndef stk500generic_h__
|
||||
#define stk500generic_h__
|
||||
|
||||
extern const char stk500generic_desc[];
|
||||
void stk500generic_initpgm (PROGRAMMER * pgm);
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
4734
src/stk500v2.c
Normal file
4734
src/stk500v2.c
Normal file
File diff suppressed because it is too large
Load Diff
63
src/stk500v2.h
Normal file
63
src/stk500v2.h
Normal file
@@ -0,0 +1,63 @@
|
||||
/*
|
||||
* avrdude - A Downloader/Uploader for AVR device programmers
|
||||
* Copyright (C) 2002-2005 Brian S. Dean <bsd@bsdhome.com>
|
||||
* Copyright (C) 2006 Joerg Wunsch <j@uriah.heep.sax.de>
|
||||
*
|
||||
* 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/* $Id$ */
|
||||
|
||||
#ifndef stk500v2_h
|
||||
#define stk500v2_h
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
extern const char stk500v2_desc[];
|
||||
extern const char stk500hvsp_desc[];
|
||||
extern const char stk500pp_desc[];
|
||||
extern const char stk500v2_jtagmkII_desc[];
|
||||
extern const char stk500v2_dragon_hvsp_desc[];
|
||||
extern const char stk500v2_dragon_isp_desc[];
|
||||
extern const char stk500v2_dragon_pp_desc[];
|
||||
extern const char stk500v2_jtag3_desc[];
|
||||
extern const char stk600_desc[];
|
||||
extern const char stk600hvsp_desc[];
|
||||
extern const char stk600pp_desc[];
|
||||
void stk500v2_initpgm (PROGRAMMER * pgm);
|
||||
void stk500hvsp_initpgm (PROGRAMMER * pgm);
|
||||
void stk500pp_initpgm (PROGRAMMER * pgm);
|
||||
void stk500v2_jtagmkII_initpgm(PROGRAMMER * pgm);
|
||||
void stk500v2_jtag3_initpgm(PROGRAMMER * pgm);
|
||||
void stk500v2_dragon_hvsp_initpgm(PROGRAMMER * pgm);
|
||||
void stk500v2_dragon_isp_initpgm(PROGRAMMER * pgm);
|
||||
void stk500v2_dragon_pp_initpgm(PROGRAMMER * pgm);
|
||||
void stk600_initpgm (PROGRAMMER * pgm);
|
||||
void stk600hvsp_initpgm (PROGRAMMER * pgm);
|
||||
void stk600pp_initpgm (PROGRAMMER * pgm);
|
||||
|
||||
void stk500v2_setup(PROGRAMMER * pgm);
|
||||
void stk500v2_teardown(PROGRAMMER * pgm);
|
||||
int stk500v2_drain(PROGRAMMER * pgm, int display);
|
||||
int stk500v2_getsync(PROGRAMMER * pgm);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
327
src/stk500v2_private.h
Normal file
327
src/stk500v2_private.h
Normal file
@@ -0,0 +1,327 @@
|
||||
//**** ATMEL AVR - A P P L I C A T I O N N O T E ************************
|
||||
//*
|
||||
//* Title: AVR068 - STK500 Communication Protocol
|
||||
//* Filename: command.h
|
||||
//* Version: 1.0
|
||||
//* Last updated: 10.01.2005
|
||||
//*
|
||||
//* Support E-mail: avr@atmel.com
|
||||
//*
|
||||
//**************************************************************************
|
||||
|
||||
// *****************[ STK message constants ]***************************
|
||||
|
||||
#define MESSAGE_START 0x1B //= ESC = 27 decimal
|
||||
#define TOKEN 0x0E
|
||||
|
||||
// *****************[ STK general command constants ]**************************
|
||||
|
||||
#define CMD_SIGN_ON 0x01
|
||||
#define CMD_SET_PARAMETER 0x02
|
||||
#define CMD_GET_PARAMETER 0x03
|
||||
#define CMD_SET_DEVICE_PARAMETERS 0x04
|
||||
#define CMD_OSCCAL 0x05
|
||||
#define CMD_LOAD_ADDRESS 0x06
|
||||
#define CMD_FIRMWARE_UPGRADE 0x07
|
||||
#define CMD_CHECK_TARGET_CONNECTION 0x0D
|
||||
#define CMD_LOAD_RC_ID_TABLE 0x0E
|
||||
#define CMD_LOAD_EC_ID_TABLE 0x0F
|
||||
|
||||
|
||||
// *****************[ STK ISP command constants ]******************************
|
||||
|
||||
#define CMD_ENTER_PROGMODE_ISP 0x10
|
||||
#define CMD_LEAVE_PROGMODE_ISP 0x11
|
||||
#define CMD_CHIP_ERASE_ISP 0x12
|
||||
#define CMD_PROGRAM_FLASH_ISP 0x13
|
||||
#define CMD_READ_FLASH_ISP 0x14
|
||||
#define CMD_PROGRAM_EEPROM_ISP 0x15
|
||||
#define CMD_READ_EEPROM_ISP 0x16
|
||||
#define CMD_PROGRAM_FUSE_ISP 0x17
|
||||
#define CMD_READ_FUSE_ISP 0x18
|
||||
#define CMD_PROGRAM_LOCK_ISP 0x19
|
||||
#define CMD_READ_LOCK_ISP 0x1A
|
||||
#define CMD_READ_SIGNATURE_ISP 0x1B
|
||||
#define CMD_READ_OSCCAL_ISP 0x1C
|
||||
#define CMD_SPI_MULTI 0x1D /* STK500v2, AVRISPmkII,
|
||||
* JTAGICEmkII */
|
||||
#define CMD_SET_SCK 0x1D /* JTAGICE3 */
|
||||
#define CMD_GET_SCK 0x1E /* JTAGICE3 */
|
||||
|
||||
// *****************[ STK PP command constants ]*******************************
|
||||
|
||||
#define CMD_ENTER_PROGMODE_PP 0x20
|
||||
#define CMD_LEAVE_PROGMODE_PP 0x21
|
||||
#define CMD_CHIP_ERASE_PP 0x22
|
||||
#define CMD_PROGRAM_FLASH_PP 0x23
|
||||
#define CMD_READ_FLASH_PP 0x24
|
||||
#define CMD_PROGRAM_EEPROM_PP 0x25
|
||||
#define CMD_READ_EEPROM_PP 0x26
|
||||
#define CMD_PROGRAM_FUSE_PP 0x27
|
||||
#define CMD_READ_FUSE_PP 0x28
|
||||
#define CMD_PROGRAM_LOCK_PP 0x29
|
||||
#define CMD_READ_LOCK_PP 0x2A
|
||||
#define CMD_READ_SIGNATURE_PP 0x2B
|
||||
#define CMD_READ_OSCCAL_PP 0x2C
|
||||
|
||||
#define CMD_SET_CONTROL_STACK 0x2D
|
||||
|
||||
// *****************[ STK HVSP command constants ]*****************************
|
||||
|
||||
#define CMD_ENTER_PROGMODE_HVSP 0x30
|
||||
#define CMD_LEAVE_PROGMODE_HVSP 0x31
|
||||
#define CMD_CHIP_ERASE_HVSP 0x32
|
||||
#define CMD_PROGRAM_FLASH_HVSP 0x33
|
||||
#define CMD_READ_FLASH_HVSP 0x34
|
||||
#define CMD_PROGRAM_EEPROM_HVSP 0x35
|
||||
#define CMD_READ_EEPROM_HVSP 0x36
|
||||
#define CMD_PROGRAM_FUSE_HVSP 0x37
|
||||
#define CMD_READ_FUSE_HVSP 0x38
|
||||
#define CMD_PROGRAM_LOCK_HVSP 0x39
|
||||
#define CMD_READ_LOCK_HVSP 0x3A
|
||||
#define CMD_READ_SIGNATURE_HVSP 0x3B
|
||||
#define CMD_READ_OSCCAL_HVSP 0x3C
|
||||
// These two are redefined since 0x30/0x31 collide
|
||||
// with the STK600 bootloader.
|
||||
#define CMD_ENTER_PROGMODE_HVSP_STK600 0x3D
|
||||
#define CMD_LEAVE_PROGMODE_HVSP_STK600 0x3E
|
||||
|
||||
// *** XPROG command constants ***
|
||||
|
||||
#define CMD_XPROG 0x50
|
||||
#define CMD_XPROG_SETMODE 0x51
|
||||
|
||||
|
||||
// *** AVR32 JTAG Programming command ***
|
||||
|
||||
#define CMD_JTAG_AVR32 0x80
|
||||
#define CMD_ENTER_PROGMODE_JTAG_AVR32 0x81
|
||||
#define CMD_LEAVE_PROGMODE_JTAG_AVR32 0x82
|
||||
|
||||
|
||||
// *** AVR JTAG Programming command ***
|
||||
|
||||
#define CMD_JTAG_AVR 0x90
|
||||
|
||||
// *****************[ STK test command constants ]***************************
|
||||
|
||||
#define CMD_ENTER_TESTMODE 0x60
|
||||
#define CMD_LEAVE_TESTMODE 0x61
|
||||
#define CMD_CHIP_WRITE 0x62
|
||||
#define CMD_PROGRAM_FLASH_PARTIAL 0x63
|
||||
#define CMD_PROGRAM_EEPROM_PARTIAL 0x64
|
||||
#define CMD_PROGRAM_SIGNATURE_ROW 0x65
|
||||
#define CMD_READ_FLASH_MARGIN 0x66
|
||||
#define CMD_READ_EEPROM_MARGIN 0x67
|
||||
#define CMD_READ_SIGNATURE_ROW_MARGIN 0x68
|
||||
#define CMD_PROGRAM_TEST_FUSE 0x69
|
||||
#define CMD_READ_TEST_FUSE 0x6A
|
||||
#define CMD_PROGRAM_HIDDEN_FUSE_LOW 0x6B
|
||||
#define CMD_READ_HIDDEN_FUSE_LOW 0x6C
|
||||
#define CMD_PROGRAM_HIDDEN_FUSE_HIGH 0x6D
|
||||
#define CMD_READ_HIDDEN_FUSE_HIGH 0x6E
|
||||
#define CMD_PROGRAM_HIDDEN_FUSE_EXT 0x6F
|
||||
#define CMD_READ_HIDDEN_FUSE_EXT 0x70
|
||||
|
||||
// *****************[ STK status constants ]***************************
|
||||
|
||||
// Success
|
||||
#define STATUS_CMD_OK 0x00
|
||||
|
||||
// Warnings
|
||||
#define STATUS_CMD_TOUT 0x80
|
||||
#define STATUS_RDY_BSY_TOUT 0x81
|
||||
#define STATUS_SET_PARAM_MISSING 0x82
|
||||
|
||||
// Errors
|
||||
#define STATUS_CMD_FAILED 0xC0
|
||||
#define STATUS_CKSUM_ERROR 0xC1
|
||||
#define STATUS_CMD_UNKNOWN 0xC9
|
||||
#define STATUS_CMD_ILLEGAL_PARAMETER 0xCA
|
||||
|
||||
// Status
|
||||
#define STATUS_ISP_READY 0x00
|
||||
#define STATUS_CONN_FAIL_MOSI 0x01
|
||||
#define STATUS_CONN_FAIL_RST 0x02
|
||||
#define STATUS_CONN_FAIL_SCK 0x04
|
||||
#define STATUS_TGT_NOT_DETECTED 0x10
|
||||
#define STATUS_TGT_REVERSE_INSERTED 0x20
|
||||
|
||||
// hw_status
|
||||
// Bits in status variable
|
||||
// Bit 0-3: Slave MCU
|
||||
// Bit 4-7: Master MCU
|
||||
|
||||
#define STATUS_AREF_ERROR 0
|
||||
// Set to '1' if AREF is short circuited
|
||||
|
||||
#define STATUS_VTG_ERROR 4
|
||||
// Set to '1' if VTG is short circuited
|
||||
|
||||
#define STATUS_RC_CARD_ERROR 5
|
||||
// Set to '1' if board id changes when board is powered
|
||||
|
||||
#define STATUS_PROGMODE 6
|
||||
// Set to '1' if board is in programming mode
|
||||
|
||||
#define STATUS_POWER_SURGE 7
|
||||
// Set to '1' if board draws excessive current
|
||||
|
||||
// *****************[ STK parameter constants ]***************************
|
||||
#define PARAM_BUILD_NUMBER_LOW 0x80 /* ??? */
|
||||
#define PARAM_BUILD_NUMBER_HIGH 0x81 /* ??? */
|
||||
#define PARAM_HW_VER 0x90
|
||||
#define PARAM_SW_MAJOR 0x91
|
||||
#define PARAM_SW_MINOR 0x92
|
||||
#define PARAM_VTARGET 0x94
|
||||
#define PARAM_VADJUST 0x95 /* STK500 only */
|
||||
#define PARAM_OSC_PSCALE 0x96 /* STK500 only */
|
||||
#define PARAM_OSC_CMATCH 0x97 /* STK500 only */
|
||||
#define PARAM_SCK_DURATION 0x98 /* STK500 only */
|
||||
#define PARAM_TOPCARD_DETECT 0x9A /* STK500 only */
|
||||
#define PARAM_STATUS 0x9C /* STK500 only */
|
||||
#define PARAM_DATA 0x9D /* STK500 only */
|
||||
#define PARAM_RESET_POLARITY 0x9E /* STK500 only, and STK600 FW
|
||||
* version <= 2.0.3 */
|
||||
#define PARAM_CONTROLLER_INIT 0x9F
|
||||
|
||||
/* STK600 parameters */
|
||||
#define PARAM_STATUS_TGT_CONN 0xA1
|
||||
#define PARAM_DISCHARGEDELAY 0xA4
|
||||
#define PARAM_SOCKETCARD_ID 0xA5
|
||||
#define PARAM_ROUTINGCARD_ID 0xA6
|
||||
#define PARAM_EXPCARD_ID 0xA7
|
||||
#define PARAM_SW_MAJOR_SLAVE1 0xA8
|
||||
#define PARAM_SW_MINOR_SLAVE1 0xA9
|
||||
#define PARAM_SW_MAJOR_SLAVE2 0xAA
|
||||
#define PARAM_SW_MINOR_SLAVE2 0xAB
|
||||
#define PARAM_BOARD_ID_STATUS 0xAD
|
||||
#define PARAM_RESET 0xB4
|
||||
|
||||
#define PARAM_JTAG_ALLOW_FULL_PAGE_STREAM 0x50
|
||||
#define PARAM_JTAG_EEPROM_PAGE_SIZE 0x52
|
||||
#define PARAM_JTAG_DAISY_BITS_BEFORE 0x53
|
||||
#define PARAM_JTAG_DAISY_BITS_AFTER 0x54
|
||||
#define PARAM_JTAG_DAISY_UNITS_BEFORE 0x55
|
||||
#define PARAM_JTAG_DAISY_UNITS_AFTER 0x56
|
||||
|
||||
// *** Parameter constants for 2 byte values ***
|
||||
#define PARAM2_SCK_DURATION 0xC0
|
||||
#define PARAM2_CLOCK_CONF 0xC1
|
||||
#define PARAM2_AREF0 0xC2
|
||||
#define PARAM2_AREF1 0xC3
|
||||
|
||||
#define PARAM2_JTAG_FLASH_SIZE_H 0xC5
|
||||
#define PARAM2_JTAG_FLASH_SIZE_L 0xC6
|
||||
#define PARAM2_JTAG_FLASH_PAGE_SIZE 0xC7
|
||||
#define PARAM2_RC_ID_TABLE_REV 0xC8
|
||||
#define PARAM2_EC_ID_TABLE_REV 0xC9
|
||||
|
||||
/* STK600 XPROG section */
|
||||
// XPROG modes
|
||||
#define XPRG_MODE_PDI 0
|
||||
#define XPRG_MODE_JTAG 1
|
||||
#define XPRG_MODE_TPI 2
|
||||
|
||||
// XPROG commands
|
||||
#define XPRG_CMD_ENTER_PROGMODE 0x01
|
||||
#define XPRG_CMD_LEAVE_PROGMODE 0x02
|
||||
#define XPRG_CMD_ERASE 0x03
|
||||
#define XPRG_CMD_WRITE_MEM 0x04
|
||||
#define XPRG_CMD_READ_MEM 0x05
|
||||
#define XPRG_CMD_CRC 0x06
|
||||
#define XPRG_CMD_SET_PARAM 0x07
|
||||
|
||||
// Memory types
|
||||
#define XPRG_MEM_TYPE_APPL 1
|
||||
#define XPRG_MEM_TYPE_BOOT 2
|
||||
#define XPRG_MEM_TYPE_EEPROM 3
|
||||
#define XPRG_MEM_TYPE_FUSE 4
|
||||
#define XPRG_MEM_TYPE_LOCKBITS 5
|
||||
#define XPRG_MEM_TYPE_USERSIG 6
|
||||
#define XPRG_MEM_TYPE_FACTORY_CALIBRATION 7
|
||||
|
||||
// Erase types
|
||||
#define XPRG_ERASE_CHIP 1
|
||||
#define XPRG_ERASE_APP 2
|
||||
#define XPRG_ERASE_BOOT 3
|
||||
#define XPRG_ERASE_EEPROM 4
|
||||
#define XPRG_ERASE_APP_PAGE 5
|
||||
#define XPRG_ERASE_BOOT_PAGE 6
|
||||
#define XPRG_ERASE_EEPROM_PAGE 7
|
||||
#define XPRG_ERASE_USERSIG 8
|
||||
#define XPRG_ERASE_CONFIG 9 // TPI only, prepare fuse write
|
||||
|
||||
// Write mode flags
|
||||
#define XPRG_MEM_WRITE_ERASE 0
|
||||
#define XPRG_MEM_WRITE_WRITE 1
|
||||
|
||||
// CRC types
|
||||
#define XPRG_CRC_APP 1
|
||||
#define XPRG_CRC_BOOT 2
|
||||
#define XPRG_CRC_FLASH 3
|
||||
|
||||
// Error codes
|
||||
#define XPRG_ERR_OK 0
|
||||
#define XPRG_ERR_FAILED 1
|
||||
#define XPRG_ERR_COLLISION 2
|
||||
#define XPRG_ERR_TIMEOUT 3
|
||||
|
||||
// XPROG parameters of different sizes
|
||||
// 4-byte address
|
||||
#define XPRG_PARAM_NVMBASE 0x01
|
||||
// 2-byte page size
|
||||
#define XPRG_PARAM_EEPPAGESIZE 0x02
|
||||
// 1-byte, undocumented TPI param
|
||||
#define XPRG_PARAM_TPI_3 0x03
|
||||
// 1-byte, undocumented TPI param
|
||||
#define XPRG_PARAM_TPI_4 0x04
|
||||
|
||||
// *****************[ STK answer constants ]***************************
|
||||
|
||||
#define ANSWER_CKSUM_ERROR 0xB0
|
||||
|
||||
/*
|
||||
* Private data for this programmer.
|
||||
*/
|
||||
struct pdata
|
||||
{
|
||||
/*
|
||||
* See stk500pp_read_byte() for an explanation of the flash and
|
||||
* EEPROM page caches.
|
||||
*/
|
||||
unsigned char *flash_pagecache;
|
||||
unsigned long flash_pageaddr;
|
||||
unsigned int flash_pagesize;
|
||||
|
||||
unsigned char *eeprom_pagecache;
|
||||
unsigned long eeprom_pageaddr;
|
||||
unsigned int eeprom_pagesize;
|
||||
|
||||
unsigned char command_sequence;
|
||||
|
||||
enum
|
||||
{
|
||||
PGMTYPE_UNKNOWN,
|
||||
PGMTYPE_STK500,
|
||||
PGMTYPE_AVRISP,
|
||||
PGMTYPE_AVRISP_MKII,
|
||||
PGMTYPE_JTAGICE_MKII,
|
||||
PGMTYPE_STK600,
|
||||
PGMTYPE_JTAGICE3
|
||||
}
|
||||
pgmtype;
|
||||
|
||||
AVRPART *lastpart;
|
||||
|
||||
/* Start address of Xmega boot area */
|
||||
unsigned long boot_start;
|
||||
|
||||
/*
|
||||
* Chained pdata for the JTAG ICE mkII backend. This is used when
|
||||
* calling the backend functions for ISP/HVSP/PP programming
|
||||
* functionality of the JTAG ICE mkII and AVR Dragon.
|
||||
*/
|
||||
void *chained_pdata;
|
||||
};
|
||||
|
||||
964
src/term.c
Normal file
964
src/term.c
Normal file
@@ -0,0 +1,964 @@
|
||||
/*
|
||||
* avrdude - A Downloader/Uploader for AVR device programmers
|
||||
* Copyright (C) 2000-2004 Brian S. Dean <bsd@bsdhome.com>
|
||||
*
|
||||
* 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/* $Id$ */
|
||||
|
||||
#include "ac_cfg.h"
|
||||
|
||||
#include <ctype.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <limits.h>
|
||||
|
||||
#if defined(HAVE_LIBREADLINE)
|
||||
#if !defined(WIN32NATIVE)
|
||||
# include <readline/readline.h>
|
||||
# include <readline/history.h>
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#include "avrdude.h"
|
||||
#include "term.h"
|
||||
|
||||
struct command {
|
||||
char * name;
|
||||
int (*func)(PROGRAMMER * pgm, struct avrpart * p, int argc, char *argv[]);
|
||||
char * desc;
|
||||
};
|
||||
|
||||
|
||||
static int cmd_dump (PROGRAMMER * pgm, struct avrpart * p,
|
||||
int argc, char *argv[]);
|
||||
|
||||
static int cmd_write (PROGRAMMER * pgm, struct avrpart * p,
|
||||
int argc, char *argv[]);
|
||||
|
||||
static int cmd_erase (PROGRAMMER * pgm, struct avrpart * p,
|
||||
int argc, char *argv[]);
|
||||
|
||||
static int cmd_sig (PROGRAMMER * pgm, struct avrpart * p,
|
||||
int argc, char *argv[]);
|
||||
|
||||
static int cmd_part (PROGRAMMER * pgm, struct avrpart * p,
|
||||
int argc, char *argv[]);
|
||||
|
||||
static int cmd_help (PROGRAMMER * pgm, struct avrpart * p,
|
||||
int argc, char *argv[]);
|
||||
|
||||
static int cmd_quit (PROGRAMMER * pgm, struct avrpart * p,
|
||||
int argc, char *argv[]);
|
||||
|
||||
static int cmd_send (PROGRAMMER * pgm, struct avrpart * p,
|
||||
int argc, char *argv[]);
|
||||
|
||||
static int cmd_parms (PROGRAMMER * pgm, struct avrpart * p,
|
||||
int argc, char *argv[]);
|
||||
|
||||
static int cmd_vtarg (PROGRAMMER * pgm, struct avrpart * p,
|
||||
int argc, char *argv[]);
|
||||
|
||||
static int cmd_varef (PROGRAMMER * pgm, struct avrpart * p,
|
||||
int argc, char *argv[]);
|
||||
|
||||
static int cmd_fosc (PROGRAMMER * pgm, struct avrpart * p,
|
||||
int argc, char *argv[]);
|
||||
|
||||
static int cmd_sck (PROGRAMMER * pgm, struct avrpart * p,
|
||||
int argc, char *argv[]);
|
||||
|
||||
static int cmd_spi (PROGRAMMER * pgm, struct avrpart * p,
|
||||
int argc, char *argv[]);
|
||||
|
||||
static int cmd_pgm (PROGRAMMER * pgm, struct avrpart * p,
|
||||
int argc, char *argv[]);
|
||||
|
||||
static int cmd_verbose (PROGRAMMER * pgm, struct avrpart * p,
|
||||
int argc, char *argv[]);
|
||||
|
||||
struct command cmd[] = {
|
||||
{ "dump", cmd_dump, "dump memory : %s <memtype> <addr> <N-Bytes>" },
|
||||
{ "read", cmd_dump, "alias for dump" },
|
||||
{ "write", cmd_write, "write memory : %s <memtype> <addr> <b1> <b2> ... <bN>" },
|
||||
{ "erase", cmd_erase, "perform a chip erase" },
|
||||
{ "sig", cmd_sig, "display device signature bytes" },
|
||||
{ "part", cmd_part, "display the current part information" },
|
||||
{ "send", cmd_send, "send a raw command : %s <b1> <b2> <b3> <b4>" },
|
||||
{ "parms", cmd_parms, "display adjustable parameters (STK500 only)" },
|
||||
{ "vtarg", cmd_vtarg, "set <V[target]> (STK500 only)" },
|
||||
{ "varef", cmd_varef, "set <V[aref]> (STK500 only)" },
|
||||
{ "fosc", cmd_fosc, "set <oscillator frequency> (STK500 only)" },
|
||||
{ "sck", cmd_sck, "set <SCK period> (STK500 only)" },
|
||||
{ "spi", cmd_spi, "enter direct SPI mode" },
|
||||
{ "pgm", cmd_pgm, "return to programming mode" },
|
||||
{ "verbose", cmd_verbose, "change verbosity" },
|
||||
{ "help", cmd_help, "help" },
|
||||
{ "?", cmd_help, "help" },
|
||||
{ "quit", cmd_quit, "quit" }
|
||||
};
|
||||
|
||||
#define NCMDS (sizeof(cmd)/sizeof(struct command))
|
||||
|
||||
|
||||
|
||||
static int spi_mode = 0;
|
||||
|
||||
static int nexttok(char * buf, char ** tok, char ** next)
|
||||
{
|
||||
char * q, * n;
|
||||
|
||||
q = buf;
|
||||
while (isspace((int)*q))
|
||||
q++;
|
||||
|
||||
/* isolate first token */
|
||||
n = q+1;
|
||||
while (*n && !isspace((int)*n))
|
||||
n++;
|
||||
|
||||
if (*n) {
|
||||
*n = 0;
|
||||
n++;
|
||||
}
|
||||
|
||||
/* find start of next token */
|
||||
while (isspace((int)*n))
|
||||
n++;
|
||||
|
||||
*tok = q;
|
||||
*next = n;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int hexdump_line(char * buffer, unsigned char * p, int n, int pad)
|
||||
{
|
||||
char * hexdata = "0123456789abcdef";
|
||||
char * b;
|
||||
int i, j;
|
||||
|
||||
b = buffer;
|
||||
|
||||
j = 0;
|
||||
for (i=0; i<n; i++) {
|
||||
if (i && ((i % 8) == 0))
|
||||
b[j++] = ' ';
|
||||
b[j++] = hexdata[(p[i] & 0xf0) >> 4];
|
||||
b[j++] = hexdata[(p[i] & 0x0f)];
|
||||
if (i < 15)
|
||||
b[j++] = ' ';
|
||||
}
|
||||
|
||||
for (i=j; i<pad; i++)
|
||||
b[i] = ' ';
|
||||
|
||||
b[i] = 0;
|
||||
|
||||
for (i=0; i<pad; i++) {
|
||||
if (!((b[i] == '0') || (b[i] == ' ')))
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
static int chardump_line(char * buffer, unsigned char * p, int n, int pad)
|
||||
{
|
||||
int i;
|
||||
char b [ 128 ];
|
||||
|
||||
for (i=0; i<n; i++) {
|
||||
memcpy(b, p, n);
|
||||
buffer[i] = '.';
|
||||
if (isalpha((int)(b[i])) || isdigit((int)(b[i])) || ispunct((int)(b[i])))
|
||||
buffer[i] = b[i];
|
||||
else if (isspace((int)(b[i])))
|
||||
buffer[i] = ' ';
|
||||
}
|
||||
|
||||
for (i=n; i<pad; i++)
|
||||
buffer[i] = ' ';
|
||||
|
||||
buffer[i] = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int hexdump_buf(FILE * f, int startaddr, unsigned char * buf, int len)
|
||||
{
|
||||
int addr;
|
||||
int n;
|
||||
unsigned char * p;
|
||||
char dst1[80];
|
||||
char dst2[80];
|
||||
|
||||
addr = startaddr;
|
||||
p = (unsigned char *)buf;
|
||||
while (len) {
|
||||
n = 16;
|
||||
if (n > len)
|
||||
n = len;
|
||||
hexdump_line(dst1, p, n, 48);
|
||||
chardump_line(dst2, p, n, 16);
|
||||
fprintf(stdout, "%04x %s |%s|\n", addr, dst1, dst2);
|
||||
len -= n;
|
||||
addr += n;
|
||||
p += n;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int cmd_dump(PROGRAMMER * pgm, struct avrpart * p,
|
||||
int argc, char * argv[])
|
||||
{
|
||||
static char prevmem[128] = {0};
|
||||
char * e;
|
||||
unsigned char * buf;
|
||||
int maxsize;
|
||||
unsigned long i;
|
||||
static unsigned long addr=0;
|
||||
static int len=64;
|
||||
AVRMEM * mem;
|
||||
char * memtype = NULL;
|
||||
int rc;
|
||||
|
||||
if (!((argc == 2) || (argc == 4))) {
|
||||
avrdude_message(MSG_INFO, "Usage: dump <memtype> [<addr> <len>]\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
memtype = argv[1];
|
||||
|
||||
if (strncmp(prevmem, memtype, strlen(memtype)) != 0) {
|
||||
addr = 0;
|
||||
len = 64;
|
||||
strncpy(prevmem, memtype, sizeof(prevmem)-1);
|
||||
prevmem[sizeof(prevmem)-1] = 0;
|
||||
}
|
||||
|
||||
mem = avr_locate_mem(p, memtype);
|
||||
if (mem == NULL) {
|
||||
avrdude_message(MSG_INFO, "\"%s\" memory type not defined for part \"%s\"\n",
|
||||
memtype, p->desc);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (argc == 4) {
|
||||
addr = strtoul(argv[2], &e, 0);
|
||||
if (*e || (e == argv[2])) {
|
||||
avrdude_message(MSG_INFO, "%s (dump): can't parse address \"%s\"\n",
|
||||
progname, argv[2]);
|
||||
return -1;
|
||||
}
|
||||
|
||||
len = strtol(argv[3], &e, 0);
|
||||
if (*e || (e == argv[3])) {
|
||||
avrdude_message(MSG_INFO, "%s (dump): can't parse length \"%s\"\n",
|
||||
progname, argv[3]);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
maxsize = mem->size;
|
||||
|
||||
if (addr >= maxsize) {
|
||||
if (argc == 2) {
|
||||
/* wrap around */
|
||||
addr = 0;
|
||||
}
|
||||
else {
|
||||
avrdude_message(MSG_INFO, "%s (dump): address 0x%05lx is out of range for %s memory\n",
|
||||
progname, addr, mem->desc);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/* trim len if nessary to not read past the end of memory */
|
||||
if ((addr + len) > maxsize)
|
||||
len = maxsize - addr;
|
||||
|
||||
buf = malloc(len);
|
||||
if (buf == NULL) {
|
||||
avrdude_message(MSG_INFO, "%s (dump): out of memory\n", progname);
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (i=0; i<len; i++) {
|
||||
rc = pgm->read_byte(pgm, p, mem, addr+i, &buf[i]);
|
||||
if (rc != 0) {
|
||||
avrdude_message(MSG_INFO, "error reading %s address 0x%05lx of part %s\n",
|
||||
mem->desc, addr+i, p->desc);
|
||||
if (rc == -1)
|
||||
avrdude_message(MSG_INFO, "read operation not supported on memory type \"%s\"\n",
|
||||
mem->desc);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
hexdump_buf(stdout, addr, buf, len);
|
||||
|
||||
fprintf(stdout, "\n");
|
||||
|
||||
free(buf);
|
||||
|
||||
addr = addr + len;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int cmd_write(PROGRAMMER * pgm, struct avrpart * p,
|
||||
int argc, char * argv[])
|
||||
{
|
||||
char * e;
|
||||
int len, maxsize;
|
||||
char * memtype;
|
||||
unsigned long addr, i;
|
||||
unsigned char * buf;
|
||||
unsigned char b;
|
||||
int rc;
|
||||
int werror;
|
||||
AVRMEM * mem;
|
||||
|
||||
if (argc < 4) {
|
||||
avrdude_message(MSG_INFO, "Usage: write <memtype> <addr> <byte1> "
|
||||
"<byte2> ... <byteN>\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
memtype = argv[1];
|
||||
|
||||
mem = avr_locate_mem(p, memtype);
|
||||
if (mem == NULL) {
|
||||
avrdude_message(MSG_INFO, "\"%s\" memory type not defined for part \"%s\"\n",
|
||||
memtype, p->desc);
|
||||
return -1;
|
||||
}
|
||||
|
||||
maxsize = mem->size;
|
||||
|
||||
addr = strtoul(argv[2], &e, 0);
|
||||
if (*e || (e == argv[2])) {
|
||||
avrdude_message(MSG_INFO, "%s (write): can't parse address \"%s\"\n",
|
||||
progname, argv[2]);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (addr > maxsize) {
|
||||
avrdude_message(MSG_INFO, "%s (write): address 0x%05lx is out of range for %s memory\n",
|
||||
progname, addr, memtype);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* number of bytes to write at the specified address */
|
||||
len = argc - 3;
|
||||
|
||||
if ((addr + len) > maxsize) {
|
||||
avrdude_message(MSG_INFO, "%s (write): selected address and # bytes exceed "
|
||||
"range for %s memory\n",
|
||||
progname, memtype);
|
||||
return -1;
|
||||
}
|
||||
|
||||
buf = malloc(len);
|
||||
if (buf == NULL) {
|
||||
avrdude_message(MSG_INFO, "%s (write): out of memory\n", progname);
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (i=3; i<argc; i++) {
|
||||
buf[i-3] = strtoul(argv[i], &e, 0);
|
||||
if (*e || (e == argv[i])) {
|
||||
avrdude_message(MSG_INFO, "%s (write): can't parse byte \"%s\"\n",
|
||||
progname, argv[i]);
|
||||
free(buf);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
pgm->err_led(pgm, OFF);
|
||||
for (werror=0, i=0; i<len; i++) {
|
||||
|
||||
rc = avr_write_byte(pgm, p, mem, addr+i, buf[i]);
|
||||
if (rc) {
|
||||
avrdude_message(MSG_INFO, "%s (write): error writing 0x%02x at 0x%05lx, rc=%d\n",
|
||||
progname, buf[i], addr+i, rc);
|
||||
if (rc == -1)
|
||||
avrdude_message(MSG_INFO, "write operation not supported on memory type \"%s\"\n",
|
||||
mem->desc);
|
||||
werror = 1;
|
||||
}
|
||||
|
||||
rc = pgm->read_byte(pgm, p, mem, addr+i, &b);
|
||||
if (b != buf[i]) {
|
||||
avrdude_message(MSG_INFO, "%s (write): error writing 0x%02x at 0x%05lx cell=0x%02x\n",
|
||||
progname, buf[i], addr+i, b);
|
||||
werror = 1;
|
||||
}
|
||||
|
||||
if (werror) {
|
||||
pgm->err_led(pgm, ON);
|
||||
}
|
||||
}
|
||||
|
||||
free(buf);
|
||||
|
||||
fprintf(stdout, "\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int cmd_send(PROGRAMMER * pgm, struct avrpart * p,
|
||||
int argc, char * argv[])
|
||||
{
|
||||
unsigned char cmd[4], res[4];
|
||||
char * e;
|
||||
int i;
|
||||
int len;
|
||||
|
||||
if (pgm->cmd == NULL) {
|
||||
avrdude_message(MSG_INFO, "The %s programmer does not support direct ISP commands.\n",
|
||||
pgm->type);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (spi_mode && (pgm->spi == NULL)) {
|
||||
avrdude_message(MSG_INFO, "The %s programmer does not support direct SPI transfers.\n",
|
||||
pgm->type);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
if ((argc > 5) || ((argc < 5) && (!spi_mode))) {
|
||||
avrdude_message(MSG_INFO, spi_mode?
|
||||
"Usage: send <byte1> [<byte2> [<byte3> [<byte4>]]]\n":
|
||||
"Usage: send <byte1> <byte2> <byte3> <byte4>\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* number of bytes to write at the specified address */
|
||||
len = argc - 1;
|
||||
|
||||
/* load command bytes */
|
||||
for (i=1; i<argc; i++) {
|
||||
cmd[i-1] = strtoul(argv[i], &e, 0);
|
||||
if (*e || (e == argv[i])) {
|
||||
avrdude_message(MSG_INFO, "%s (send): can't parse byte \"%s\"\n",
|
||||
progname, argv[i]);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
pgm->err_led(pgm, OFF);
|
||||
|
||||
if (spi_mode)
|
||||
pgm->spi(pgm, cmd, res, argc-1);
|
||||
else
|
||||
pgm->cmd(pgm, cmd, res);
|
||||
|
||||
/*
|
||||
* display results
|
||||
*/
|
||||
avrdude_message(MSG_INFO, "results:");
|
||||
for (i=0; i<len; i++)
|
||||
avrdude_message(MSG_INFO, " %02x", res[i]);
|
||||
avrdude_message(MSG_INFO, "\n");
|
||||
|
||||
fprintf(stdout, "\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int cmd_erase(PROGRAMMER * pgm, struct avrpart * p,
|
||||
int argc, char * argv[])
|
||||
{
|
||||
avrdude_message(MSG_INFO, "%s: erasing chip\n", progname);
|
||||
pgm->chip_erase(pgm, p);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int cmd_part(PROGRAMMER * pgm, struct avrpart * p,
|
||||
int argc, char * argv[])
|
||||
{
|
||||
fprintf(stdout, "\n");
|
||||
avr_display(stdout, p, "", 0);
|
||||
fprintf(stdout, "\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int cmd_sig(PROGRAMMER * pgm, struct avrpart * p,
|
||||
int argc, char * argv[])
|
||||
{
|
||||
int i;
|
||||
int rc;
|
||||
AVRMEM * m;
|
||||
|
||||
rc = avr_signature(pgm, p);
|
||||
if (rc != 0) {
|
||||
avrdude_message(MSG_INFO, "error reading signature data, rc=%d\n",
|
||||
rc);
|
||||
}
|
||||
|
||||
m = avr_locate_mem(p, "signature");
|
||||
if (m == NULL) {
|
||||
avrdude_message(MSG_INFO, "signature data not defined for device \"%s\"\n",
|
||||
p->desc);
|
||||
}
|
||||
else {
|
||||
fprintf(stdout, "Device signature = 0x");
|
||||
for (i=0; i<m->size; i++)
|
||||
fprintf(stdout, "%02x", m->buf[i]);
|
||||
fprintf(stdout, "\n\n");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int cmd_quit(PROGRAMMER * pgm, struct avrpart * p,
|
||||
int argc, char * argv[])
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
static int cmd_parms(PROGRAMMER * pgm, struct avrpart * p,
|
||||
int argc, char * argv[])
|
||||
{
|
||||
if (pgm->print_parms == NULL) {
|
||||
avrdude_message(MSG_INFO, "%s (parms): the %s programmer does not support "
|
||||
"adjustable parameters\n",
|
||||
progname, pgm->type);
|
||||
return -1;
|
||||
}
|
||||
pgm->print_parms(pgm);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int cmd_vtarg(PROGRAMMER * pgm, struct avrpart * p,
|
||||
int argc, char * argv[])
|
||||
{
|
||||
int rc;
|
||||
double v;
|
||||
char *endp;
|
||||
|
||||
if (argc != 2) {
|
||||
avrdude_message(MSG_INFO, "Usage: vtarg <value>\n");
|
||||
return -1;
|
||||
}
|
||||
v = strtod(argv[1], &endp);
|
||||
if (endp == argv[1]) {
|
||||
avrdude_message(MSG_INFO, "%s (vtarg): can't parse voltage \"%s\"\n",
|
||||
progname, argv[1]);
|
||||
return -1;
|
||||
}
|
||||
if (pgm->set_vtarget == NULL) {
|
||||
avrdude_message(MSG_INFO, "%s (vtarg): the %s programmer cannot set V[target]\n",
|
||||
progname, pgm->type);
|
||||
return -2;
|
||||
}
|
||||
if ((rc = pgm->set_vtarget(pgm, v)) != 0) {
|
||||
avrdude_message(MSG_INFO, "%s (vtarg): failed to set V[target] (rc = %d)\n",
|
||||
progname, rc);
|
||||
return -3;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int cmd_fosc(PROGRAMMER * pgm, struct avrpart * p,
|
||||
int argc, char * argv[])
|
||||
{
|
||||
int rc;
|
||||
double v;
|
||||
char *endp;
|
||||
|
||||
if (argc != 2) {
|
||||
avrdude_message(MSG_INFO, "Usage: fosc <value>[M|k] | off\n");
|
||||
return -1;
|
||||
}
|
||||
v = strtod(argv[1], &endp);
|
||||
if (endp == argv[1]) {
|
||||
if (strcmp(argv[1], "off") == 0)
|
||||
v = 0.0;
|
||||
else {
|
||||
avrdude_message(MSG_INFO, "%s (fosc): can't parse frequency \"%s\"\n",
|
||||
progname, argv[1]);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
if (*endp == 'm' || *endp == 'M')
|
||||
v *= 1e6;
|
||||
else if (*endp == 'k' || *endp == 'K')
|
||||
v *= 1e3;
|
||||
if (pgm->set_fosc == NULL) {
|
||||
avrdude_message(MSG_INFO, "%s (fosc): the %s programmer cannot set oscillator frequency\n",
|
||||
progname, pgm->type);
|
||||
return -2;
|
||||
}
|
||||
if ((rc = pgm->set_fosc(pgm, v)) != 0) {
|
||||
avrdude_message(MSG_INFO, "%s (fosc): failed to set oscillator frequency (rc = %d)\n",
|
||||
progname, rc);
|
||||
return -3;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int cmd_sck(PROGRAMMER * pgm, struct avrpart * p,
|
||||
int argc, char * argv[])
|
||||
{
|
||||
int rc;
|
||||
double v;
|
||||
char *endp;
|
||||
|
||||
if (argc != 2) {
|
||||
avrdude_message(MSG_INFO, "Usage: sck <value>\n");
|
||||
return -1;
|
||||
}
|
||||
v = strtod(argv[1], &endp);
|
||||
if (endp == argv[1]) {
|
||||
avrdude_message(MSG_INFO, "%s (sck): can't parse period \"%s\"\n",
|
||||
progname, argv[1]);
|
||||
return -1;
|
||||
}
|
||||
v *= 1e-6; /* Convert from microseconds to seconds. */
|
||||
if (pgm->set_sck_period == NULL) {
|
||||
avrdude_message(MSG_INFO, "%s (sck): the %s programmer cannot set SCK period\n",
|
||||
progname, pgm->type);
|
||||
return -2;
|
||||
}
|
||||
if ((rc = pgm->set_sck_period(pgm, v)) != 0) {
|
||||
avrdude_message(MSG_INFO, "%s (sck): failed to set SCK period (rc = %d)\n",
|
||||
progname, rc);
|
||||
return -3;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int cmd_varef(PROGRAMMER * pgm, struct avrpart * p,
|
||||
int argc, char * argv[])
|
||||
{
|
||||
int rc;
|
||||
unsigned int chan;
|
||||
double v;
|
||||
char *endp;
|
||||
|
||||
if (argc != 2 && argc != 3) {
|
||||
avrdude_message(MSG_INFO, "Usage: varef [channel] <value>\n");
|
||||
return -1;
|
||||
}
|
||||
if (argc == 2) {
|
||||
chan = 0;
|
||||
v = strtod(argv[1], &endp);
|
||||
if (endp == argv[1]) {
|
||||
avrdude_message(MSG_INFO, "%s (varef): can't parse voltage \"%s\"\n",
|
||||
progname, argv[1]);
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
chan = strtoul(argv[1], &endp, 10);
|
||||
if (endp == argv[1]) {
|
||||
avrdude_message(MSG_INFO, "%s (varef): can't parse channel \"%s\"\n",
|
||||
progname, argv[1]);
|
||||
return -1;
|
||||
}
|
||||
v = strtod(argv[2], &endp);
|
||||
if (endp == argv[2]) {
|
||||
avrdude_message(MSG_INFO, "%s (varef): can't parse voltage \"%s\"\n",
|
||||
progname, argv[2]);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
if (pgm->set_varef == NULL) {
|
||||
avrdude_message(MSG_INFO, "%s (varef): the %s programmer cannot set V[aref]\n",
|
||||
progname, pgm->type);
|
||||
return -2;
|
||||
}
|
||||
if ((rc = pgm->set_varef(pgm, chan, v)) != 0) {
|
||||
avrdude_message(MSG_INFO, "%s (varef): failed to set V[aref] (rc = %d)\n",
|
||||
progname, rc);
|
||||
return -3;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int cmd_help(PROGRAMMER * pgm, struct avrpart * p,
|
||||
int argc, char * argv[])
|
||||
{
|
||||
int i;
|
||||
|
||||
fprintf(stdout, "Valid commands:\n\n");
|
||||
for (i=0; i<NCMDS; i++) {
|
||||
fprintf(stdout, " %-6s : ", cmd[i].name);
|
||||
fprintf(stdout, cmd[i].desc, cmd[i].name);
|
||||
fprintf(stdout, "\n");
|
||||
}
|
||||
fprintf(stdout,
|
||||
"\nUse the 'part' command to display valid memory types for use with the\n"
|
||||
"'dump' and 'write' commands.\n\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cmd_spi(PROGRAMMER * pgm, struct avrpart * p,
|
||||
int argc, char * argv[])
|
||||
{
|
||||
pgm->setpin(pgm, PIN_AVR_RESET, 1);
|
||||
spi_mode = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cmd_pgm(PROGRAMMER * pgm, struct avrpart * p,
|
||||
int argc, char * argv[])
|
||||
{
|
||||
pgm->setpin(pgm, PIN_AVR_RESET, 0);
|
||||
spi_mode = 0;
|
||||
pgm->initialize(pgm, p);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cmd_verbose(PROGRAMMER * pgm, struct avrpart * p,
|
||||
int argc, char * argv[])
|
||||
{
|
||||
int nverb;
|
||||
char *endp;
|
||||
|
||||
if (argc != 1 && argc != 2) {
|
||||
avrdude_message(MSG_INFO, "Usage: verbose [<value>]\n");
|
||||
return -1;
|
||||
}
|
||||
if (argc == 1) {
|
||||
avrdude_message(MSG_INFO, "Verbosity level: %d\n", verbose);
|
||||
return 0;
|
||||
}
|
||||
nverb = strtol(argv[1], &endp, 0);
|
||||
if (endp == argv[2]) {
|
||||
avrdude_message(MSG_INFO, "%s: can't parse verbosity level \"%s\"\n",
|
||||
progname, argv[2]);
|
||||
return -1;
|
||||
}
|
||||
if (nverb < 0) {
|
||||
avrdude_message(MSG_INFO, "%s: verbosity level must be positive: %d\n",
|
||||
progname, nverb);
|
||||
return -1;
|
||||
}
|
||||
verbose = nverb;
|
||||
avrdude_message(MSG_INFO, "New verbosity level: %d\n", verbose);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tokenize(char * s, char *** argv)
|
||||
{
|
||||
int i, n, l, k, nargs, offset;
|
||||
int len, slen;
|
||||
char * buf;
|
||||
int bufsize;
|
||||
char ** bufv;
|
||||
char * bufp;
|
||||
char * q, * r;
|
||||
char * nbuf;
|
||||
char ** av;
|
||||
|
||||
slen = strlen(s);
|
||||
|
||||
/*
|
||||
* initialize allow for 20 arguments, use realloc to grow this if
|
||||
* necessary
|
||||
*/
|
||||
nargs = 20;
|
||||
bufsize = slen + 20;
|
||||
buf = malloc(bufsize);
|
||||
bufv = (char **) malloc(nargs*sizeof(char *));
|
||||
for (i=0; i<nargs; i++) {
|
||||
bufv[i] = NULL;
|
||||
}
|
||||
buf[0] = 0;
|
||||
|
||||
n = 0;
|
||||
l = 0;
|
||||
nbuf = buf;
|
||||
r = s;
|
||||
while (*r) {
|
||||
nexttok(r, &q, &r);
|
||||
strcpy(nbuf, q);
|
||||
bufv[n] = nbuf;
|
||||
len = strlen(q);
|
||||
l += len + 1;
|
||||
nbuf += len + 1;
|
||||
nbuf[0] = 0;
|
||||
n++;
|
||||
if ((n % 20) == 0) {
|
||||
/* realloc space for another 20 args */
|
||||
bufsize += 20;
|
||||
nargs += 20;
|
||||
bufp = buf;
|
||||
buf = realloc(buf, bufsize);
|
||||
bufv = realloc(bufv, nargs*sizeof(char *));
|
||||
nbuf = &buf[l];
|
||||
/* correct bufv pointers */
|
||||
k = buf - bufp;
|
||||
for (i=0; i<n; i++) {
|
||||
bufv[i] = bufv[i] + k;
|
||||
}
|
||||
for (i=n; i<nargs; i++)
|
||||
bufv[i] = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* We have parsed all the args, n == argc, bufv contains an array of
|
||||
* pointers to each arg, and buf points to one memory block that
|
||||
* contains all the args, back to back, seperated by a nul
|
||||
* terminator. Consilidate bufv and buf into one big memory block
|
||||
* so that the code that calls us, will have an easy job of freeing
|
||||
* this memory.
|
||||
*/
|
||||
av = (char **) malloc(slen + n + (n+1)*sizeof(char *));
|
||||
q = (char *)&av[n+1];
|
||||
memcpy(q, buf, l);
|
||||
for (i=0; i<n; i++) {
|
||||
offset = bufv[i] - buf;
|
||||
av[i] = q + offset;
|
||||
}
|
||||
av[i] = NULL;
|
||||
|
||||
free(buf);
|
||||
free(bufv);
|
||||
|
||||
*argv = av;
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
|
||||
static int do_cmd(PROGRAMMER * pgm, struct avrpart * p,
|
||||
int argc, char * argv[])
|
||||
{
|
||||
int i;
|
||||
int hold;
|
||||
int len;
|
||||
|
||||
len = strlen(argv[0]);
|
||||
hold = -1;
|
||||
for (i=0; i<NCMDS; i++) {
|
||||
if (strcasecmp(argv[0], cmd[i].name) == 0) {
|
||||
return cmd[i].func(pgm, p, argc, argv);
|
||||
}
|
||||
else if (strncasecmp(argv[0], cmd[i].name, len)==0) {
|
||||
if (hold != -1) {
|
||||
avrdude_message(MSG_INFO, "%s: command \"%s\" is ambiguous\n",
|
||||
progname, argv[0]);
|
||||
return -1;
|
||||
}
|
||||
hold = i;
|
||||
}
|
||||
}
|
||||
|
||||
if (hold != -1)
|
||||
return cmd[hold].func(pgm, p, argc, argv);
|
||||
|
||||
avrdude_message(MSG_INFO, "%s: invalid command \"%s\"\n",
|
||||
progname, argv[0]);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
char * terminal_get_input(const char *prompt)
|
||||
{
|
||||
#if defined(HAVE_LIBREADLINE) && !defined(WIN32NATIVE)
|
||||
char *input;
|
||||
input = readline(prompt);
|
||||
if ((input != NULL) && (strlen(input) >= 1))
|
||||
add_history(input);
|
||||
|
||||
return input;
|
||||
#else
|
||||
char input[256];
|
||||
printf("%s", prompt);
|
||||
if (fgets(input, sizeof(input), stdin))
|
||||
{
|
||||
/* FIXME: readline strips the '\n', should this too? */
|
||||
return strdup(input);
|
||||
}
|
||||
else
|
||||
return NULL;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
int terminal_mode(PROGRAMMER * pgm, struct avrpart * p)
|
||||
{
|
||||
char * cmdbuf;
|
||||
int i;
|
||||
char * q;
|
||||
int rc;
|
||||
int argc;
|
||||
char ** argv;
|
||||
|
||||
rc = 0;
|
||||
while ((cmdbuf = terminal_get_input("avrdude> ")) != NULL) {
|
||||
/*
|
||||
* find the start of the command, skipping any white space
|
||||
*/
|
||||
q = cmdbuf;
|
||||
while (*q && isspace((int)*q))
|
||||
q++;
|
||||
|
||||
/* skip blank lines and comments */
|
||||
if (!*q || (*q == '#'))
|
||||
continue;
|
||||
|
||||
/* tokenize command line */
|
||||
argc = tokenize(q, &argv);
|
||||
|
||||
fprintf(stdout, ">>> ");
|
||||
for (i=0; i<argc; i++)
|
||||
fprintf(stdout, "%s ", argv[i]);
|
||||
fprintf(stdout, "\n");
|
||||
|
||||
/* run the command */
|
||||
rc = do_cmd(pgm, p, argc, argv);
|
||||
free(argv);
|
||||
if (rc > 0) {
|
||||
rc = 0;
|
||||
break;
|
||||
}
|
||||
free(cmdbuf);
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
37
src/term.h
Normal file
37
src/term.h
Normal file
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* avrdude - A Downloader/Uploader for AVR device programmers
|
||||
* Copyright (C) 2000-2004 Brian S. Dean <bsd@bsdhome.com>
|
||||
*
|
||||
* 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/* $Id$ */
|
||||
|
||||
#ifndef term_h
|
||||
#define term_h
|
||||
|
||||
#include "libavrdude.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
int terminal_mode(PROGRAMMER * pgm, struct avrpart * p);
|
||||
char * terminal_get_input(const char *prompt);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
76
src/tpi.h
Normal file
76
src/tpi.h
Normal file
@@ -0,0 +1,76 @@
|
||||
/*
|
||||
* avrdude - A Downloader/Uploader for AVR device programmers
|
||||
* Copyright (C) 2011 Darell Tan <darell.tan@gmail.com>
|
||||
*
|
||||
* 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/* $Id$ */
|
||||
|
||||
#ifndef tpi_h
|
||||
#define tpi_h
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
static const unsigned char tpi_skey[] = { 0x12, 0x89, 0xAB, 0x45, 0xCD, 0xD8, 0x88, 0xFF };
|
||||
|
||||
/* registers */
|
||||
#define TPI_REG_TPIIR 0x0F
|
||||
|
||||
#define TPI_IDENT_CODE 0x80
|
||||
|
||||
#define TPI_REG_TPIPCR 0x02
|
||||
#define TPI_REG_TPISR 0x00
|
||||
|
||||
#define TPI_REG_TPISR_NVMEN (1 << 1)
|
||||
|
||||
/* TPI commands */
|
||||
#define TPI_CMD_SLD 0x20
|
||||
#define TPI_CMD_SLD_PI 0x24
|
||||
#define TPI_CMD_SIN 0x10
|
||||
#define TPI_CMD_SOUT 0x90
|
||||
#define TPI_CMD_SSTCS 0xC0
|
||||
#define TPI_CMD_SST 0x60
|
||||
#define TPI_CMD_SST_PI 0x64
|
||||
|
||||
#define TPI_CMD_SLDCS 0x80
|
||||
#define TPI_CMD_SSTPR 0x68
|
||||
#define TPI_CMD_SKEY 0xE0
|
||||
|
||||
/* for TPI_CMD_SIN & TPI_CMD_SOUT */
|
||||
#define TPI_SIO_ADDR(x) ((x & 0x30) << 1 | (x & 0x0F))
|
||||
|
||||
/* ATtiny4/5/9/10 I/O registers */
|
||||
#define TPI_IOREG_NVMCSR 0x32
|
||||
#define TPI_IOREG_NVMCMD 0x33
|
||||
|
||||
/* bit for NVMCSR */
|
||||
#define TPI_IOREG_NVMCSR_NVMBSY (1 << 7)
|
||||
|
||||
/* NVM commands */
|
||||
#define TPI_NVMCMD_NO_OPERATION 0x00
|
||||
#define TPI_NVMCMD_CHIP_ERASE 0x10
|
||||
#define TPI_NVMCMD_SECTION_ERASE 0x14
|
||||
#define TPI_NVMCMD_WORD_WRITE 0x1D
|
||||
|
||||
static const unsigned char tpi_skey_cmd[] = { TPI_CMD_SKEY, 0xff, 0x88, 0xd8, 0xcd, 0x45, 0xab, 0x89, 0x12 };
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
392
src/update.c
Normal file
392
src/update.c
Normal file
@@ -0,0 +1,392 @@
|
||||
/*
|
||||
* avrdude - A Downloader/Uploader for AVR device programmers
|
||||
* Copyright (C) 2000-2005 Brian S. Dean <bsd@bsdhome.com>
|
||||
* Copyright (C) 2007 Joerg Wunsch
|
||||
*
|
||||
* 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/* $Id$ */
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
|
||||
#include "avrdude.h"
|
||||
#include "libavrdude.h"
|
||||
|
||||
UPDATE * parse_op(char * s)
|
||||
{
|
||||
char buf[1024];
|
||||
char * p, * cp, c;
|
||||
UPDATE * upd;
|
||||
int i;
|
||||
size_t fnlen;
|
||||
|
||||
upd = (UPDATE *)malloc(sizeof(UPDATE));
|
||||
if (upd == NULL) {
|
||||
avrdude_message(MSG_INFO, "%s: out of memory\n", progname);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
i = 0;
|
||||
p = s;
|
||||
while ((i < (sizeof(buf)-1) && *p && (*p != ':')))
|
||||
buf[i++] = *p++;
|
||||
buf[i] = 0;
|
||||
|
||||
if (*p != ':') {
|
||||
upd->memtype = NULL; /* default memtype, "flash", or "application" */
|
||||
upd->op = DEVICE_WRITE;
|
||||
upd->filename = (char *)malloc(strlen(buf) + 1);
|
||||
if (upd->filename == NULL) {
|
||||
avrdude_message(MSG_INFO, "%s: out of memory\n", progname);
|
||||
exit(1);
|
||||
}
|
||||
strcpy(upd->filename, buf);
|
||||
upd->format = FMT_AUTO;
|
||||
return upd;
|
||||
}
|
||||
|
||||
upd->memtype = (char *)malloc(strlen(buf)+1);
|
||||
if (upd->memtype == NULL) {
|
||||
avrdude_message(MSG_INFO, "%s: out of memory\n", progname);
|
||||
exit(1);
|
||||
}
|
||||
strcpy(upd->memtype, buf);
|
||||
|
||||
p++;
|
||||
if (*p == 'r') {
|
||||
upd->op = DEVICE_READ;
|
||||
}
|
||||
else if (*p == 'w') {
|
||||
upd->op = DEVICE_WRITE;
|
||||
}
|
||||
else if (*p == 'v') {
|
||||
upd->op = DEVICE_VERIFY;
|
||||
}
|
||||
else {
|
||||
avrdude_message(MSG_INFO, "%s: invalid I/O mode '%c' in update specification\n",
|
||||
progname, *p);
|
||||
avrdude_message(MSG_INFO, " allowed values are:\n"
|
||||
" r = read device\n"
|
||||
" w = write device\n"
|
||||
" v = verify device\n");
|
||||
free(upd->memtype);
|
||||
free(upd);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
p++;
|
||||
|
||||
if (*p != ':') {
|
||||
avrdude_message(MSG_INFO, "%s: invalid update specification\n", progname);
|
||||
free(upd->memtype);
|
||||
free(upd);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
p++;
|
||||
|
||||
/*
|
||||
* Now, parse the filename component. Instead of looking for the
|
||||
* leftmost possible colon delimiter, we look for the rightmost one.
|
||||
* If we found one, we do have a trailing :format specifier, and
|
||||
* process it. Otherwise, the remainder of the string is our file
|
||||
* name component. That way, the file name itself is allowed to
|
||||
* contain a colon itself (e. g. C:/some/file.hex), except the
|
||||
* optional format specifier becomes mandatory then.
|
||||
*/
|
||||
cp = p;
|
||||
p = strrchr(cp, ':');
|
||||
if (p == NULL) {
|
||||
// missing format, default to "AUTO" for write and verify,
|
||||
// and to binary for read operations:
|
||||
upd->format = upd->op == DEVICE_READ? FMT_RBIN: FMT_AUTO;
|
||||
fnlen = strlen(cp);
|
||||
upd->filename = (char *)malloc(fnlen + 1);
|
||||
} else {
|
||||
fnlen = p - cp;
|
||||
upd->filename = (char *)malloc(fnlen +1);
|
||||
c = *++p;
|
||||
if (c && p[1])
|
||||
/* More than one char - force failure below. */
|
||||
c = '?';
|
||||
switch (c) {
|
||||
case 'a': upd->format = FMT_AUTO; break;
|
||||
case 's': upd->format = FMT_SREC; break;
|
||||
case 'i': upd->format = FMT_IHEX; break;
|
||||
case 'r': upd->format = FMT_RBIN; break;
|
||||
case 'e': upd->format = FMT_ELF; break;
|
||||
case 'm': upd->format = FMT_IMM; break;
|
||||
case 'b': upd->format = FMT_BIN; break;
|
||||
case 'd': upd->format = FMT_DEC; break;
|
||||
case 'h': upd->format = FMT_HEX; break;
|
||||
case 'o': upd->format = FMT_OCT; break;
|
||||
default:
|
||||
avrdude_message(MSG_INFO, "%s: invalid file format '%s' in update specifier\n",
|
||||
progname, p);
|
||||
free(upd->memtype);
|
||||
free(upd);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if (upd->filename == NULL) {
|
||||
avrdude_message(MSG_INFO, "%s: out of memory\n", progname);
|
||||
free(upd->memtype);
|
||||
free(upd);
|
||||
return NULL;
|
||||
}
|
||||
memcpy(upd->filename, cp, fnlen);
|
||||
upd->filename[fnlen] = 0;
|
||||
|
||||
return upd;
|
||||
}
|
||||
|
||||
UPDATE * dup_update(UPDATE * upd)
|
||||
{
|
||||
UPDATE * u;
|
||||
|
||||
u = (UPDATE *)malloc(sizeof(UPDATE));
|
||||
if (u == NULL) {
|
||||
avrdude_message(MSG_INFO, "%s: out of memory\n", progname);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
memcpy(u, upd, sizeof(UPDATE));
|
||||
|
||||
if (upd->memtype != NULL)
|
||||
u->memtype = strdup(upd->memtype);
|
||||
else
|
||||
u->memtype = NULL;
|
||||
u->filename = strdup(upd->filename);
|
||||
|
||||
return u;
|
||||
}
|
||||
|
||||
UPDATE * new_update(int op, char * memtype, int filefmt, char * filename)
|
||||
{
|
||||
UPDATE * u;
|
||||
|
||||
u = (UPDATE *)malloc(sizeof(UPDATE));
|
||||
if (u == NULL) {
|
||||
avrdude_message(MSG_INFO, "%s: out of memory\n", progname);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
u->memtype = strdup(memtype);
|
||||
u->filename = strdup(filename);
|
||||
u->op = op;
|
||||
u->format = filefmt;
|
||||
|
||||
return u;
|
||||
}
|
||||
|
||||
void free_update(UPDATE * u)
|
||||
{
|
||||
if (u != NULL) {
|
||||
if(u->memtype != NULL) {
|
||||
free(u->memtype);
|
||||
u->memtype = NULL;
|
||||
}
|
||||
if(u->filename != NULL) {
|
||||
free(u->filename);
|
||||
u->filename = NULL;
|
||||
}
|
||||
free(u);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int do_op(PROGRAMMER * pgm, struct avrpart * p, UPDATE * upd, enum updateflags flags)
|
||||
{
|
||||
struct avrpart * v;
|
||||
AVRMEM * mem;
|
||||
int size, vsize;
|
||||
int rc;
|
||||
|
||||
mem = avr_locate_mem(p, upd->memtype);
|
||||
if (mem == NULL) {
|
||||
avrdude_message(MSG_INFO, "\"%s\" memory type not defined for part \"%s\"\n",
|
||||
upd->memtype, p->desc);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (upd->op == DEVICE_READ) {
|
||||
/*
|
||||
* read out the specified device memory and write it to a file
|
||||
*/
|
||||
if (upd->format == FMT_IMM) {
|
||||
avrdude_message(MSG_INFO,
|
||||
"%s: Invalid file format 'immediate' for output\n",
|
||||
progname, upd->filename);
|
||||
return -1;
|
||||
}
|
||||
if (quell_progress < 2) {
|
||||
avrdude_message(MSG_INFO, "%s: reading %s memory:\n",
|
||||
progname, mem->desc);
|
||||
}
|
||||
report_progress(0,1,"Reading");
|
||||
rc = avr_read(pgm, p, upd->memtype, 0);
|
||||
if (rc < 0) {
|
||||
avrdude_message(MSG_INFO, "%s: failed to read all of %s memory, rc=%d\n",
|
||||
progname, mem->desc, rc);
|
||||
return -1;
|
||||
}
|
||||
report_progress(1,1,NULL);
|
||||
size = rc;
|
||||
|
||||
if (quell_progress < 2) {
|
||||
if (rc == 0)
|
||||
avrdude_message(MSG_INFO, "%s: Flash is empty, resulting file has no contents.\n",
|
||||
progname);
|
||||
avrdude_message(MSG_INFO, "%s: writing output file \"%s\"\n",
|
||||
progname,
|
||||
strcmp(upd->filename, "-")==0 ? "<stdout>" : upd->filename);
|
||||
}
|
||||
rc = fileio(FIO_WRITE, upd->filename, upd->format, p, upd->memtype, size);
|
||||
if (rc < 0) {
|
||||
avrdude_message(MSG_INFO, "%s: write to file '%s' failed\n",
|
||||
progname, upd->filename);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
else if (upd->op == DEVICE_WRITE) {
|
||||
/*
|
||||
* write the selected device memory using data from a file; first
|
||||
* read the data from the specified file
|
||||
*/
|
||||
if (quell_progress < 2) {
|
||||
avrdude_message(MSG_INFO, "%s: reading input file \"%s\"\n",
|
||||
progname,
|
||||
strcmp(upd->filename, "-")==0 ? "<stdin>" : upd->filename);
|
||||
}
|
||||
rc = fileio(FIO_READ, upd->filename, upd->format, p, upd->memtype, -1);
|
||||
if (rc < 0) {
|
||||
avrdude_message(MSG_INFO, "%s: read from file '%s' failed\n",
|
||||
progname, upd->filename);
|
||||
return -1;
|
||||
}
|
||||
size = rc;
|
||||
|
||||
/*
|
||||
* write the buffer contents to the selected memory type
|
||||
*/
|
||||
if (quell_progress < 2) {
|
||||
avrdude_message(MSG_INFO, "%s: writing %s (%d bytes):\n",
|
||||
progname, mem->desc, size);
|
||||
}
|
||||
|
||||
if (!(flags & UF_NOWRITE)) {
|
||||
report_progress(0,1,"Writing");
|
||||
rc = avr_write(pgm, p, upd->memtype, size, (flags & UF_AUTO_ERASE) != 0);
|
||||
report_progress(1,1,NULL);
|
||||
}
|
||||
else {
|
||||
/*
|
||||
* test mode, don't actually write to the chip, output the buffer
|
||||
* to stdout in intel hex instead
|
||||
*/
|
||||
rc = fileio(FIO_WRITE, "-", FMT_IHEX, p, upd->memtype, size);
|
||||
}
|
||||
|
||||
if (rc < 0) {
|
||||
avrdude_message(MSG_INFO, "%s: failed to write %s memory, rc=%d\n",
|
||||
progname, mem->desc, rc);
|
||||
return -1;
|
||||
}
|
||||
|
||||
vsize = rc;
|
||||
|
||||
if (quell_progress < 2) {
|
||||
avrdude_message(MSG_INFO, "%s: %d bytes of %s written\n", progname,
|
||||
vsize, mem->desc);
|
||||
}
|
||||
|
||||
}
|
||||
else if (upd->op == DEVICE_VERIFY) {
|
||||
/*
|
||||
* verify that the in memory file (p->mem[AVR_M_FLASH|AVR_M_EEPROM])
|
||||
* is the same as what is on the chip
|
||||
*/
|
||||
pgm->vfy_led(pgm, ON);
|
||||
|
||||
if (quell_progress < 2) {
|
||||
avrdude_message(MSG_INFO, "%s: verifying %s memory against %s:\n",
|
||||
progname, mem->desc, upd->filename);
|
||||
|
||||
avrdude_message(MSG_INFO, "%s: load data %s data from input file %s:\n",
|
||||
progname, mem->desc, upd->filename);
|
||||
}
|
||||
|
||||
rc = fileio(FIO_READ, upd->filename, upd->format, p, upd->memtype, -1);
|
||||
if (rc < 0) {
|
||||
avrdude_message(MSG_INFO, "%s: read from file '%s' failed\n",
|
||||
progname, upd->filename);
|
||||
return -1;
|
||||
}
|
||||
v = avr_dup_part(p);
|
||||
size = rc;
|
||||
if (quell_progress < 2) {
|
||||
avrdude_message(MSG_INFO, "%s: input file %s contains %d bytes\n",
|
||||
progname, upd->filename, size);
|
||||
avrdude_message(MSG_INFO, "%s: reading on-chip %s data:\n",
|
||||
progname, mem->desc);
|
||||
}
|
||||
|
||||
report_progress (0,1,"Reading");
|
||||
rc = avr_read(pgm, p, upd->memtype, v);
|
||||
if (rc < 0) {
|
||||
avrdude_message(MSG_INFO, "%s: failed to read all of %s memory, rc=%d\n",
|
||||
progname, mem->desc, rc);
|
||||
pgm->err_led(pgm, ON);
|
||||
avr_free_part(v);
|
||||
return -1;
|
||||
}
|
||||
report_progress (1,1,NULL);
|
||||
|
||||
|
||||
|
||||
if (quell_progress < 2) {
|
||||
avrdude_message(MSG_INFO, "%s: verifying ...\n", progname);
|
||||
}
|
||||
rc = avr_verify(p, v, upd->memtype, size);
|
||||
if (rc < 0) {
|
||||
avrdude_message(MSG_INFO, "%s: verification error; content mismatch\n",
|
||||
progname);
|
||||
pgm->err_led(pgm, ON);
|
||||
avr_free_part(v);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (quell_progress < 2) {
|
||||
avrdude_message(MSG_INFO, "%s: %d bytes of %s verified\n",
|
||||
progname, rc, mem->desc);
|
||||
}
|
||||
|
||||
pgm->vfy_led(pgm, OFF);
|
||||
avr_free_part(v);
|
||||
}
|
||||
else {
|
||||
avrdude_message(MSG_INFO, "%s: invalid update operation (%d) requested\n",
|
||||
progname, upd->op);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
357
src/usb_hidapi.c
Normal file
357
src/usb_hidapi.c
Normal file
@@ -0,0 +1,357 @@
|
||||
/*
|
||||
* avrdude - A Downloader/Uploader for AVR device programmers
|
||||
* Copyright (C) 2016 Joerg Wunsch
|
||||
*
|
||||
* 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/* $Id$ */
|
||||
|
||||
/*
|
||||
* USB interface via libhidapi for avrdude.
|
||||
*/
|
||||
|
||||
#include "ac_cfg.h"
|
||||
#if defined(HAVE_LIBHIDAPI)
|
||||
|
||||
|
||||
#include <ctype.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/time.h>
|
||||
#include <wchar.h>
|
||||
|
||||
#include <hidapi/hidapi.h>
|
||||
|
||||
#include "avrdude.h"
|
||||
#include "libavrdude.h"
|
||||
|
||||
#include "usbdevs.h"
|
||||
|
||||
#if defined(WIN32NATIVE)
|
||||
/* someone has defined "interface" to "struct" in Cygwin */
|
||||
# undef interface
|
||||
#endif
|
||||
|
||||
/*
|
||||
* The "baud" parameter is meaningless for USB devices, so we reuse it
|
||||
* to pass the desired USB device ID.
|
||||
*/
|
||||
static int usbhid_open(char * port, union pinfo pinfo, union filedescriptor *fd)
|
||||
{
|
||||
hid_device *dev;
|
||||
char *serno, *cp2;
|
||||
size_t x;
|
||||
unsigned char usbbuf[USBDEV_MAX_XFER_3 + 1];
|
||||
|
||||
if (fd->usb.max_xfer == 0)
|
||||
fd->usb.max_xfer = USBDEV_MAX_XFER_3;
|
||||
|
||||
/*
|
||||
* The syntax for usb devices is defined as:
|
||||
*
|
||||
* -P usb[:serialnumber]
|
||||
*
|
||||
* See if we've got a serial number passed here. The serial number
|
||||
* might contain colons which we remove below, and we compare it
|
||||
* right-to-left, so only the least significant nibbles need to be
|
||||
* specified.
|
||||
*/
|
||||
if ((serno = strchr(port, ':')) != NULL)
|
||||
{
|
||||
/* first, drop all colons there if any */
|
||||
cp2 = ++serno;
|
||||
|
||||
while ((cp2 = strchr(cp2, ':')) != NULL)
|
||||
{
|
||||
x = strlen(cp2) - 1;
|
||||
memmove(cp2, cp2 + 1, x);
|
||||
cp2[x] = '\0';
|
||||
}
|
||||
|
||||
if (strlen(serno) > 12)
|
||||
{
|
||||
avrdude_message(MSG_INFO, "%s: usbhid_open(): invalid serial number \"%s\"\n",
|
||||
progname, serno);
|
||||
return -1;
|
||||
}
|
||||
|
||||
wchar_t wserno[15];
|
||||
mbstowcs(wserno, serno, 15);
|
||||
size_t serlen = strlen(serno);
|
||||
|
||||
/*
|
||||
* Now, try finding all devices matching VID:PID, and compare
|
||||
* their serial numbers against the requested one.
|
||||
*/
|
||||
struct hid_device_info *list, *walk;
|
||||
list = hid_enumerate(pinfo.usbinfo.vid, pinfo.usbinfo.pid);
|
||||
if (list == NULL)
|
||||
return -1;
|
||||
|
||||
walk = list;
|
||||
while (walk)
|
||||
{
|
||||
avrdude_message(MSG_NOTICE, "%s: usbhid_open(): Found %ls, serno: %ls\n",
|
||||
progname, walk->product_string, walk->serial_number);
|
||||
size_t slen = wcslen(walk->serial_number);
|
||||
if (slen >= serlen &&
|
||||
wcscmp(walk->serial_number + slen - serlen, wserno) == 0)
|
||||
{
|
||||
/* found matching serial number */
|
||||
break;
|
||||
}
|
||||
avrdude_message(MSG_DEBUG, "%s: usbhid_open(): serial number doesn't match\n",
|
||||
progname);
|
||||
walk = walk->next;
|
||||
}
|
||||
if (walk == NULL)
|
||||
{
|
||||
avrdude_message(MSG_INFO, "%s: usbhid_open(): No matching device found\n",
|
||||
progname);
|
||||
hid_free_enumeration(list);
|
||||
return -1;
|
||||
}
|
||||
avrdude_message(MSG_DEBUG, "%s: usbhid_open(): Opening path %s\n",
|
||||
progname, walk->path);
|
||||
dev = hid_open_path(walk->path);
|
||||
hid_free_enumeration(list);
|
||||
if (dev == NULL)
|
||||
{
|
||||
avrdude_message(MSG_INFO,
|
||||
"%s: usbhid_open(): Found device, but hid_open_path() failed\n",
|
||||
progname);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/*
|
||||
* No serial number requested, pass straight to hid_open()
|
||||
*/
|
||||
dev = hid_open(pinfo.usbinfo.vid, pinfo.usbinfo.pid, NULL);
|
||||
if (dev == NULL)
|
||||
{
|
||||
avrdude_message(MSG_INFO, "%s: usbhid_open(): No device found\n",
|
||||
progname);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
fd->usb.handle = dev;
|
||||
|
||||
/*
|
||||
* Try finding out the endpoint size. Alas, libhidapi doesn't
|
||||
* provide us with an API function for that, nor for the report
|
||||
* descriptor (which also contains that information).
|
||||
*
|
||||
* Since the Atmel tools a very picky to only respond to incoming
|
||||
* packets that have full size, we need to know whether our device
|
||||
* handles 512-byte data (JTAGICE3 in CMSIS-DAP mode, or AtmelICE,
|
||||
* both on USB 2.0 connections), or 64-byte data only (both these on
|
||||
* USB 1.1 connections, or mEDBG devices).
|
||||
*
|
||||
* In order to find out, we send a CMSIS-DAP DAP_Info command
|
||||
* (0x00), with an ID of 0xFF (get maximum packet size). In theory,
|
||||
* this gets us the desired information, but this suffers from a
|
||||
* chicken-and-egg problem: the request must be sent with a
|
||||
* full-sized packet lest the ICE won't answer. Thus, we send a
|
||||
* 64-byte packet first, and if we don't get a timely reply,
|
||||
* complete that request by sending another 448 bytes, and hope it
|
||||
* will eventually reply.
|
||||
*
|
||||
* Note that libhidapi always requires a report ID as the first
|
||||
* byte. If the target doesn't use report IDs (Atmel targets
|
||||
* don't), this first byte must be 0x00. However, the length must
|
||||
* be incremented by one, as the report ID will be omitted by the
|
||||
* hidapi library.
|
||||
*/
|
||||
if (pinfo.usbinfo.vid == USB_VENDOR_ATMEL)
|
||||
{
|
||||
avrdude_message(MSG_DEBUG, "%s: usbhid_open(): Probing for max. packet size\n",
|
||||
progname);
|
||||
memset(usbbuf, 0, sizeof usbbuf);
|
||||
usbbuf[0] = 0; /* no HID reports used */
|
||||
usbbuf[1] = 0; /* DAP_Info */
|
||||
usbbuf[2] = 0xFF; /* get max. packet size */
|
||||
|
||||
hid_write(dev, usbbuf, 65);
|
||||
fd->usb.max_xfer = 64; /* first guess */
|
||||
|
||||
memset(usbbuf, 0, sizeof usbbuf);
|
||||
int res = hid_read_timeout(dev, usbbuf, 10 /* bytes */, 50 /* milliseconds */);
|
||||
if (res == 0) {
|
||||
/* no timely response, assume 512 byte size */
|
||||
hid_write(dev, usbbuf, (512 - 64) + 1);
|
||||
fd->usb.max_xfer = 512;
|
||||
res = hid_read_timeout(dev, usbbuf, 10, 50);
|
||||
}
|
||||
if (res <= 0) {
|
||||
avrdude_message(MSG_INFO, "%s: usbhid_open(): No response from device\n",
|
||||
progname);
|
||||
hid_close(dev);
|
||||
return -1;
|
||||
}
|
||||
if (usbbuf[0] != 0 || usbbuf[1] != 2) {
|
||||
avrdude_message(MSG_INFO,
|
||||
"%s: usbhid_open(): Unexpected reply to DAP_Info: 0x%02x 0x%02x\n",
|
||||
progname, usbbuf[0], usbbuf[1]);
|
||||
} else {
|
||||
fd->usb.max_xfer = usbbuf[2] + (usbbuf[3] << 8);
|
||||
avrdude_message(MSG_DEBUG,
|
||||
"%s: usbhid_open(): Setting max_xfer from DAP_Info response to %d\n",
|
||||
progname, fd->usb.max_xfer);
|
||||
}
|
||||
}
|
||||
if (fd->usb.max_xfer > USBDEV_MAX_XFER_3) {
|
||||
avrdude_message(MSG_INFO,
|
||||
"%s: usbhid_open(): Unexpected max size %d, reducing to %d\n",
|
||||
progname, fd->usb.max_xfer, USBDEV_MAX_XFER_3);
|
||||
fd->usb.max_xfer = USBDEV_MAX_XFER_3;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void usbhid_close(union filedescriptor *fd)
|
||||
{
|
||||
hid_device *udev = (hid_device *)fd->usb.handle;
|
||||
|
||||
if (udev == NULL)
|
||||
return;
|
||||
|
||||
hid_close(udev);
|
||||
}
|
||||
|
||||
|
||||
static int usbhid_send(union filedescriptor *fd, const unsigned char *bp, size_t mlen)
|
||||
{
|
||||
hid_device *udev = (hid_device *)fd->usb.handle;
|
||||
int rv;
|
||||
int i = mlen;
|
||||
const unsigned char * p = bp;
|
||||
unsigned char usbbuf[USBDEV_MAX_XFER_3 + 1];
|
||||
|
||||
|
||||
int tx_size;
|
||||
|
||||
if (udev == NULL)
|
||||
return -1;
|
||||
|
||||
tx_size = (mlen < USBDEV_MAX_XFER_3)? mlen: USBDEV_MAX_XFER_3;
|
||||
usbbuf[0] = 0; /* no report ID used */
|
||||
memcpy(usbbuf + 1, bp, tx_size);
|
||||
rv = hid_write(udev, usbbuf, tx_size + 1);
|
||||
if (rv < 0) {
|
||||
avrdude_message(MSG_INFO, "%s: Failed to write %d bytes to USB\n",
|
||||
progname, tx_size);
|
||||
return -1;
|
||||
}
|
||||
if (rv != tx_size + 1)
|
||||
avrdude_message(MSG_INFO, "%s: Short write to USB: %d bytes out of %d written\n",
|
||||
progname, rv, tx_size + 1);
|
||||
|
||||
if (verbose > 4)
|
||||
{
|
||||
avrdude_message(MSG_TRACE2, "%s: Sent: ", progname);
|
||||
|
||||
while (i) {
|
||||
unsigned char c = *p;
|
||||
if (isprint(c)) {
|
||||
avrdude_message(MSG_TRACE2, "%c ", c);
|
||||
}
|
||||
else {
|
||||
avrdude_message(MSG_TRACE2, ". ");
|
||||
}
|
||||
avrdude_message(MSG_TRACE2, "[%02x] ", c);
|
||||
|
||||
p++;
|
||||
i--;
|
||||
}
|
||||
avrdude_message(MSG_TRACE2, "\n");
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int usbhid_recv(union filedescriptor *fd, unsigned char *buf, size_t nbytes)
|
||||
{
|
||||
hid_device *udev = (hid_device *)fd->usb.handle;
|
||||
int i, rv;
|
||||
unsigned char * p = buf;
|
||||
|
||||
if (udev == NULL)
|
||||
return -1;
|
||||
|
||||
rv = i = hid_read_timeout(udev, buf, nbytes, 300);
|
||||
if (i != nbytes)
|
||||
avrdude_message(MSG_INFO,
|
||||
"%s: Short read, read only %d out of %u bytes\n",
|
||||
progname, i, nbytes);
|
||||
|
||||
if (verbose > 4)
|
||||
{
|
||||
avrdude_message(MSG_TRACE2, "%s: Recv: ", progname);
|
||||
|
||||
while (i) {
|
||||
unsigned char c = *p;
|
||||
if (isprint(c)) {
|
||||
avrdude_message(MSG_TRACE2, "%c ", c);
|
||||
}
|
||||
else {
|
||||
avrdude_message(MSG_TRACE2, ". ");
|
||||
}
|
||||
avrdude_message(MSG_TRACE2, "[%02x] ", c);
|
||||
|
||||
p++;
|
||||
i--;
|
||||
}
|
||||
avrdude_message(MSG_TRACE2, "\n");
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
static int usbhid_drain(union filedescriptor *fd, int display)
|
||||
{
|
||||
/*
|
||||
* There is not much point in trying to flush any data
|
||||
* on an USB endpoint, as the endpoint is supposed to
|
||||
* start afresh after being configured from the host.
|
||||
*
|
||||
* As trying to flush the data here caused strange effects
|
||||
* in some situations (see
|
||||
* https://savannah.nongnu.org/bugs/index.php?43268 )
|
||||
* better avoid it.
|
||||
*/
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Device descriptor.
|
||||
*/
|
||||
struct serial_device usbhid_serdev =
|
||||
{
|
||||
.open = usbhid_open,
|
||||
.close = usbhid_close,
|
||||
.send = usbhid_send,
|
||||
.recv = usbhid_recv,
|
||||
.drain = usbhid_drain,
|
||||
.flags = SERDEV_FL_NONE,
|
||||
};
|
||||
|
||||
#endif /* HAVE_LIBHIDAPI */
|
||||
615
src/usb_libusb.c
Normal file
615
src/usb_libusb.c
Normal file
@@ -0,0 +1,615 @@
|
||||
/*
|
||||
* avrdude - A Downloader/Uploader for AVR device programmers
|
||||
* Copyright (C) 2005,2006 Joerg Wunsch
|
||||
* Copyright (C) 2006 David Moore
|
||||
*
|
||||
* 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/* $Id$ */
|
||||
|
||||
/*
|
||||
* USB interface via libusb for avrdude.
|
||||
*/
|
||||
|
||||
#include "ac_cfg.h"
|
||||
#if defined(HAVE_LIBUSB)
|
||||
|
||||
|
||||
#include <ctype.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
#if defined(HAVE_USB_H)
|
||||
# include <usb.h>
|
||||
#elif defined(HAVE_LUSB0_USB_H)
|
||||
# include <lusb0_usb.h>
|
||||
#else
|
||||
# error "libusb needs either <usb.h> or <lusb0_usb.h>"
|
||||
#endif
|
||||
|
||||
#include "avrdude.h"
|
||||
#include "libavrdude.h"
|
||||
|
||||
#include "usbdevs.h"
|
||||
|
||||
#if defined(WIN32NATIVE)
|
||||
/* someone has defined "interface" to "struct" in Cygwin */
|
||||
# undef interface
|
||||
#endif
|
||||
|
||||
static char usbbuf[USBDEV_MAX_XFER_3];
|
||||
static int buflen = -1, bufptr;
|
||||
|
||||
static int usb_interface;
|
||||
|
||||
/*
|
||||
* The "baud" parameter is meaningless for USB devices, so we reuse it
|
||||
* to pass the desired USB device ID.
|
||||
*/
|
||||
static int usbdev_open(char * port, union pinfo pinfo, union filedescriptor *fd)
|
||||
{
|
||||
char string[256];
|
||||
char product[256];
|
||||
struct usb_bus *bus;
|
||||
struct usb_device *dev;
|
||||
usb_dev_handle *udev;
|
||||
char *serno, *cp2;
|
||||
int i;
|
||||
int iface;
|
||||
size_t x;
|
||||
|
||||
/*
|
||||
* The syntax for usb devices is defined as:
|
||||
*
|
||||
* -P usb[:serialnumber]
|
||||
*
|
||||
* See if we've got a serial number passed here. The serial number
|
||||
* might contain colons which we remove below, and we compare it
|
||||
* right-to-left, so only the least significant nibbles need to be
|
||||
* specified.
|
||||
*/
|
||||
if ((serno = strchr(port, ':')) != NULL)
|
||||
{
|
||||
/* first, drop all colons there if any */
|
||||
cp2 = ++serno;
|
||||
|
||||
while ((cp2 = strchr(cp2, ':')) != NULL)
|
||||
{
|
||||
x = strlen(cp2) - 1;
|
||||
memmove(cp2, cp2 + 1, x);
|
||||
cp2[x] = '\0';
|
||||
}
|
||||
|
||||
if (strlen(serno) > 12)
|
||||
{
|
||||
avrdude_message(MSG_INFO, "%s: usbdev_open(): invalid serial number \"%s\"\n",
|
||||
progname, serno);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (fd->usb.max_xfer == 0)
|
||||
fd->usb.max_xfer = USBDEV_MAX_XFER_MKII;
|
||||
|
||||
usb_init();
|
||||
|
||||
usb_find_busses();
|
||||
usb_find_devices();
|
||||
|
||||
for (bus = usb_get_busses(); bus; bus = bus->next)
|
||||
{
|
||||
for (dev = bus->devices; dev; dev = dev->next)
|
||||
{
|
||||
if (dev->descriptor.idVendor == pinfo.usbinfo.vid &&
|
||||
dev->descriptor.idProduct == pinfo.usbinfo.pid)
|
||||
{
|
||||
udev = usb_open(dev);
|
||||
if (udev)
|
||||
{
|
||||
/* yeah, we found something */
|
||||
if (usb_get_string_simple(udev,
|
||||
dev->descriptor.iSerialNumber,
|
||||
string, sizeof(string)) < 0)
|
||||
{
|
||||
avrdude_message(MSG_INFO, "%s: usb_open(): cannot read serial number \"%s\"\n",
|
||||
progname, usb_strerror());
|
||||
/*
|
||||
* On some systems, libusb appears to have
|
||||
* problems sending control messages. Catch the
|
||||
* benign case where the user did not request a
|
||||
* particular serial number, so we could
|
||||
* continue anyway.
|
||||
*/
|
||||
if (serno != NULL)
|
||||
return -1; /* no chance */
|
||||
else
|
||||
strcpy(string, "[unknown]");
|
||||
}
|
||||
|
||||
if (usb_get_string_simple(udev,
|
||||
dev->descriptor.iProduct,
|
||||
product, sizeof(product)) < 0)
|
||||
{
|
||||
avrdude_message(MSG_INFO, "%s: usb_open(): cannot read product name \"%s\"\n",
|
||||
progname, usb_strerror());
|
||||
strcpy(product, "[unnamed product]");
|
||||
}
|
||||
/*
|
||||
* The CMSIS-DAP specification mandates the string
|
||||
* "CMSIS-DAP" must be present somewhere in the
|
||||
* product name string for a device compliant to
|
||||
* that protocol. Use this for the decisision
|
||||
* whether we have to search for a HID interface
|
||||
* below.
|
||||
*/
|
||||
if(strstr(product, "CMSIS-DAP") != NULL)
|
||||
{
|
||||
pinfo.usbinfo.flags |= PINFO_FL_USEHID;
|
||||
/* The JTAGICE3 running the CMSIS-DAP firmware doesn't
|
||||
* use a separate endpoint for event reception. */
|
||||
fd->usb.eep = 0;
|
||||
}
|
||||
|
||||
if(strstr(product, "mEDBG") != NULL)
|
||||
{
|
||||
/* The AVR Xplained Mini uses different endpoints. */
|
||||
fd->usb.rep = 0x81;
|
||||
fd->usb.wep = 0x02;
|
||||
}
|
||||
|
||||
avrdude_message(MSG_NOTICE, "%s: usbdev_open(): Found %s, serno: %s\n",
|
||||
progname, product, string);
|
||||
if (serno != NULL)
|
||||
{
|
||||
/*
|
||||
* See if the serial number requested by the
|
||||
* user matches what we found, matching
|
||||
* right-to-left.
|
||||
*/
|
||||
x = strlen(string) - strlen(serno);
|
||||
if (strcasecmp(string + x, serno) != 0)
|
||||
{
|
||||
avrdude_message(MSG_DEBUG, "%s: usbdev_open(): serial number doesn't match\n",
|
||||
progname);
|
||||
usb_close(udev);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (dev->config == NULL)
|
||||
{
|
||||
avrdude_message(MSG_INFO, "%s: usbdev_open(): USB device has no configuration\n",
|
||||
progname);
|
||||
goto trynext;
|
||||
}
|
||||
|
||||
if (usb_set_configuration(udev, dev->config[0].bConfigurationValue))
|
||||
{
|
||||
avrdude_message(MSG_INFO, "%s: usbdev_open(): WARNING: failed to set configuration %d: %s\n",
|
||||
progname, dev->config[0].bConfigurationValue,
|
||||
usb_strerror());
|
||||
/* let's hope it has already been configured */
|
||||
// goto trynext;
|
||||
}
|
||||
|
||||
for (iface = 0; iface < dev->config[0].bNumInterfaces; iface++)
|
||||
{
|
||||
usb_interface = dev->config[0].interface[iface].altsetting[0].bInterfaceNumber;
|
||||
#ifdef LIBUSB_HAS_GET_DRIVER_NP
|
||||
/*
|
||||
* Many Linux systems attach the usbhid driver
|
||||
* by default to any HID-class device. On
|
||||
* those, the driver needs to be detached before
|
||||
* we can claim the interface.
|
||||
*/
|
||||
(void)usb_detach_kernel_driver_np(udev, usb_interface);
|
||||
#endif
|
||||
if (usb_claim_interface(udev, usb_interface))
|
||||
{
|
||||
avrdude_message(MSG_INFO, "%s: usbdev_open(): error claiming interface %d: %s\n",
|
||||
progname, usb_interface, usb_strerror());
|
||||
}
|
||||
else
|
||||
{
|
||||
if (pinfo.usbinfo.flags & PINFO_FL_USEHID)
|
||||
{
|
||||
/* only consider an interface that is of class HID */
|
||||
if (dev->config[0].interface[iface].altsetting[0].bInterfaceClass !=
|
||||
USB_CLASS_HID)
|
||||
continue;
|
||||
fd->usb.use_interrupt_xfer = 1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (iface == dev->config[0].bNumInterfaces)
|
||||
{
|
||||
avrdude_message(MSG_INFO, "%s: usbdev_open(): no usable interface found\n",
|
||||
progname);
|
||||
goto trynext;
|
||||
}
|
||||
|
||||
fd->usb.handle = udev;
|
||||
if (fd->usb.rep == 0)
|
||||
{
|
||||
/* Try finding out what our read endpoint is. */
|
||||
for (i = 0; i < dev->config[0].interface[iface].altsetting[0].bNumEndpoints; i++)
|
||||
{
|
||||
int possible_ep = dev->config[0].interface[iface].altsetting[0].
|
||||
endpoint[i].bEndpointAddress;
|
||||
|
||||
if ((possible_ep & USB_ENDPOINT_DIR_MASK) != 0)
|
||||
{
|
||||
avrdude_message(MSG_NOTICE2, "%s: usbdev_open(): using read endpoint 0x%02x\n",
|
||||
progname, possible_ep);
|
||||
fd->usb.rep = possible_ep;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (fd->usb.rep == 0)
|
||||
{
|
||||
avrdude_message(MSG_INFO, "%s: usbdev_open(): cannot find a read endpoint, using 0x%02x\n",
|
||||
progname, USBDEV_BULK_EP_READ_MKII);
|
||||
fd->usb.rep = USBDEV_BULK_EP_READ_MKII;
|
||||
}
|
||||
}
|
||||
for (i = 0; i < dev->config[0].interface[iface].altsetting[0].bNumEndpoints; i++)
|
||||
{
|
||||
if ((dev->config[0].interface[iface].altsetting[0].endpoint[i].bEndpointAddress == fd->usb.rep ||
|
||||
dev->config[0].interface[iface].altsetting[0].endpoint[i].bEndpointAddress == fd->usb.wep) &&
|
||||
dev->config[0].interface[iface].altsetting[0].endpoint[i].wMaxPacketSize < fd->usb.max_xfer)
|
||||
{
|
||||
avrdude_message(MSG_NOTICE, "%s: max packet size expected %d, but found %d due to EP 0x%02x's wMaxPacketSize\n",
|
||||
progname,
|
||||
fd->usb.max_xfer,
|
||||
dev->config[0].interface[iface].altsetting[0].endpoint[i].wMaxPacketSize,
|
||||
dev->config[0].interface[iface].altsetting[0].endpoint[i].bEndpointAddress);
|
||||
fd->usb.max_xfer = dev->config[0].interface[iface].altsetting[0].endpoint[i].wMaxPacketSize;
|
||||
}
|
||||
}
|
||||
if (pinfo.usbinfo.flags & PINFO_FL_USEHID)
|
||||
{
|
||||
if (usb_control_msg(udev, 0x21, 0x0a /* SET_IDLE */, 0, 0, NULL, 0, 100) < 0)
|
||||
avrdude_message(MSG_INFO, "%s: usbdev_open(): SET_IDLE failed\n", progname);
|
||||
}
|
||||
return 0;
|
||||
trynext:
|
||||
usb_close(udev);
|
||||
}
|
||||
else
|
||||
avrdude_message(MSG_INFO, "%s: usbdev_open(): cannot open device: %s\n",
|
||||
progname, usb_strerror());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ((pinfo.usbinfo.flags & PINFO_FL_SILENT) == 0)
|
||||
avrdude_message(MSG_NOTICE, "%s: usbdev_open(): did not find any%s USB device \"%s\" (0x%04x:0x%04x)\n",
|
||||
progname, serno? " (matching)": "", port,
|
||||
(unsigned)pinfo.usbinfo.vid, (unsigned)pinfo.usbinfo.pid);
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void usbdev_close(union filedescriptor *fd)
|
||||
{
|
||||
usb_dev_handle *udev = (usb_dev_handle *)fd->usb.handle;
|
||||
|
||||
if (udev == NULL)
|
||||
return;
|
||||
|
||||
(void)usb_release_interface(udev, usb_interface);
|
||||
|
||||
#if defined(__linux__)
|
||||
/*
|
||||
* Without this reset, the AVRISP mkII seems to stall the second
|
||||
* time we try to connect to it. This is not necessary on
|
||||
* FreeBSD.
|
||||
*/
|
||||
usb_reset(udev);
|
||||
#endif
|
||||
|
||||
usb_close(udev);
|
||||
}
|
||||
|
||||
|
||||
static int usbdev_send(union filedescriptor *fd, const unsigned char *bp, size_t mlen)
|
||||
{
|
||||
usb_dev_handle *udev = (usb_dev_handle *)fd->usb.handle;
|
||||
int rv;
|
||||
int i = mlen;
|
||||
const unsigned char * p = bp;
|
||||
int tx_size;
|
||||
|
||||
if (udev == NULL)
|
||||
return -1;
|
||||
|
||||
/*
|
||||
* Split the frame into multiple packets. It's important to make
|
||||
* sure we finish with a short packet, or else the device won't know
|
||||
* the frame is finished. For example, if we need to send 64 bytes,
|
||||
* we must send a packet of length 64 followed by a packet of length
|
||||
* 0.
|
||||
*/
|
||||
do {
|
||||
tx_size = (mlen < fd->usb.max_xfer)? mlen: fd->usb.max_xfer;
|
||||
if (fd->usb.use_interrupt_xfer)
|
||||
rv = usb_interrupt_write(udev, fd->usb.wep, (char *)bp, tx_size, 10000);
|
||||
else
|
||||
rv = usb_bulk_write(udev, fd->usb.wep, (char *)bp, tx_size, 10000);
|
||||
if (rv != tx_size)
|
||||
{
|
||||
avrdude_message(MSG_INFO, "%s: usbdev_send(): wrote %d out of %d bytes, err = %s\n",
|
||||
progname, rv, tx_size, usb_strerror());
|
||||
return -1;
|
||||
}
|
||||
bp += tx_size;
|
||||
mlen -= tx_size;
|
||||
} while (mlen > 0);
|
||||
|
||||
if (verbose > 3)
|
||||
{
|
||||
avrdude_message(MSG_TRACE, "%s: Sent: ", progname);
|
||||
|
||||
while (i) {
|
||||
unsigned char c = *p;
|
||||
if (isprint(c)) {
|
||||
avrdude_message(MSG_TRACE, "%c ", c);
|
||||
}
|
||||
else {
|
||||
avrdude_message(MSG_TRACE, ". ");
|
||||
}
|
||||
avrdude_message(MSG_TRACE, "[%02x] ", c);
|
||||
|
||||
p++;
|
||||
i--;
|
||||
}
|
||||
avrdude_message(MSG_TRACE, "\n");
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* As calls to usb_bulk_read() result in exactly one USB request, we
|
||||
* have to buffer the read results ourselves, so the single-char read
|
||||
* requests performed by the upper layers will be handled. In order
|
||||
* to do this, we maintain a private buffer of what we've got so far,
|
||||
* and transparently issue another USB read request if the buffer is
|
||||
* empty and more data are requested.
|
||||
*/
|
||||
static int
|
||||
usb_fill_buf(usb_dev_handle *udev, int maxsize, int ep, int use_interrupt_xfer)
|
||||
{
|
||||
int rv;
|
||||
|
||||
if (use_interrupt_xfer)
|
||||
rv = usb_interrupt_read(udev, ep, usbbuf, maxsize, 10000);
|
||||
else
|
||||
rv = usb_bulk_read(udev, ep, usbbuf, maxsize, 10000);
|
||||
if (rv < 0)
|
||||
{
|
||||
avrdude_message(MSG_NOTICE2, "%s: usb_fill_buf(): usb_%s_read() error %s\n",
|
||||
progname, (use_interrupt_xfer? "interrupt": "bulk"),
|
||||
usb_strerror());
|
||||
return -1;
|
||||
}
|
||||
|
||||
buflen = rv;
|
||||
bufptr = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int usbdev_recv(union filedescriptor *fd, unsigned char *buf, size_t nbytes)
|
||||
{
|
||||
usb_dev_handle *udev = (usb_dev_handle *)fd->usb.handle;
|
||||
int i, amnt;
|
||||
unsigned char * p = buf;
|
||||
|
||||
if (udev == NULL)
|
||||
return -1;
|
||||
|
||||
for (i = 0; nbytes > 0;)
|
||||
{
|
||||
if (buflen <= bufptr)
|
||||
{
|
||||
if (usb_fill_buf(udev, fd->usb.max_xfer, fd->usb.rep, fd->usb.use_interrupt_xfer) < 0)
|
||||
return -1;
|
||||
}
|
||||
amnt = buflen - bufptr > nbytes? nbytes: buflen - bufptr;
|
||||
memcpy(buf + i, usbbuf + bufptr, amnt);
|
||||
bufptr += amnt;
|
||||
nbytes -= amnt;
|
||||
i += amnt;
|
||||
}
|
||||
|
||||
if (verbose > 4)
|
||||
{
|
||||
avrdude_message(MSG_TRACE2, "%s: Recv: ", progname);
|
||||
|
||||
while (i) {
|
||||
unsigned char c = *p;
|
||||
if (isprint(c)) {
|
||||
avrdude_message(MSG_TRACE2, "%c ", c);
|
||||
}
|
||||
else {
|
||||
avrdude_message(MSG_TRACE2, ". ");
|
||||
}
|
||||
avrdude_message(MSG_TRACE2, "[%02x] ", c);
|
||||
|
||||
p++;
|
||||
i--;
|
||||
}
|
||||
avrdude_message(MSG_TRACE2, "\n");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* This version of recv keeps reading packets until we receive a short
|
||||
* packet. Then, the entire frame is assembled and returned to the
|
||||
* user. The length will be unknown in advance, so we return the
|
||||
* length as the return value of this function, or -1 in case of an
|
||||
* error.
|
||||
*
|
||||
* This is used for the AVRISP mkII device.
|
||||
*/
|
||||
static int usbdev_recv_frame(union filedescriptor *fd, unsigned char *buf, size_t nbytes)
|
||||
{
|
||||
usb_dev_handle *udev = (usb_dev_handle *)fd->usb.handle;
|
||||
int rv, n;
|
||||
int i;
|
||||
unsigned char * p = buf;
|
||||
|
||||
if (udev == NULL)
|
||||
return -1;
|
||||
|
||||
/* If there's an event EP, and it has data pending, return it first. */
|
||||
if (fd->usb.eep != 0)
|
||||
{
|
||||
rv = usb_bulk_read(udev, fd->usb.eep, usbbuf,
|
||||
fd->usb.max_xfer, 1);
|
||||
if (rv > 4)
|
||||
{
|
||||
memcpy(buf, usbbuf, rv);
|
||||
n = rv;
|
||||
n |= USB_RECV_FLAG_EVENT;
|
||||
goto printout;
|
||||
}
|
||||
else if (rv > 0)
|
||||
{
|
||||
avrdude_message(MSG_INFO, "Short event len = %d, ignored.\n", rv);
|
||||
/* fallthrough */
|
||||
}
|
||||
}
|
||||
|
||||
n = 0;
|
||||
do
|
||||
{
|
||||
if (fd->usb.use_interrupt_xfer)
|
||||
rv = usb_interrupt_read(udev, fd->usb.rep, usbbuf,
|
||||
fd->usb.max_xfer, 10000);
|
||||
else
|
||||
rv = usb_bulk_read(udev, fd->usb.rep, usbbuf,
|
||||
fd->usb.max_xfer, 10000);
|
||||
if (rv < 0)
|
||||
{
|
||||
avrdude_message(MSG_NOTICE2, "%s: usbdev_recv_frame(): usb_%s_read(): %s\n",
|
||||
progname, (fd->usb.use_interrupt_xfer? "interrupt": "bulk"),
|
||||
usb_strerror());
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (rv <= nbytes)
|
||||
{
|
||||
memcpy (buf, usbbuf, rv);
|
||||
buf += rv;
|
||||
}
|
||||
else
|
||||
{
|
||||
return -1; // buffer overflow
|
||||
}
|
||||
|
||||
n += rv;
|
||||
nbytes -= rv;
|
||||
}
|
||||
while (nbytes > 0 && rv == fd->usb.max_xfer);
|
||||
|
||||
/*
|
||||
this ends when the buffer is completly filled (nbytes=0) or was too small (nbytes< 0)
|
||||
or a short packet is found.
|
||||
however we cannot say for nbytes=0 that there was really a packet completed,
|
||||
we had to check the last rv value than for a short packet,
|
||||
but what happens if the packet does not end with a short packet?
|
||||
and what if the buffer is filled without the packet was completed?
|
||||
|
||||
preconditions:
|
||||
expected packet is not a multiple of usb.max_xfer. (prevents further waiting)
|
||||
|
||||
expected packet is shorter than the provided buffer (so it cannot filled completely)
|
||||
or buffer size is not a multiple of usb.max_xfer. (so it can clearly detected if the buffer was overflown.)
|
||||
*/
|
||||
|
||||
printout:
|
||||
if (verbose > 3)
|
||||
{
|
||||
i = n & USB_RECV_LENGTH_MASK;
|
||||
avrdude_message(MSG_TRACE, "%s: Recv: ", progname);
|
||||
|
||||
while (i) {
|
||||
unsigned char c = *p;
|
||||
if (isprint(c)) {
|
||||
avrdude_message(MSG_TRACE, "%c ", c);
|
||||
}
|
||||
else {
|
||||
avrdude_message(MSG_TRACE, ". ");
|
||||
}
|
||||
avrdude_message(MSG_TRACE, "[%02x] ", c);
|
||||
|
||||
p++;
|
||||
i--;
|
||||
}
|
||||
avrdude_message(MSG_TRACE, "\n");
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
static int usbdev_drain(union filedescriptor *fd, int display)
|
||||
{
|
||||
/*
|
||||
* There is not much point in trying to flush any data
|
||||
* on an USB endpoint, as the endpoint is supposed to
|
||||
* start afresh after being configured from the host.
|
||||
*
|
||||
* As trying to flush the data here caused strange effects
|
||||
* in some situations (see
|
||||
* https://savannah.nongnu.org/bugs/index.php?43268 )
|
||||
* better avoid it.
|
||||
*/
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Device descriptor for the JTAG ICE mkII.
|
||||
*/
|
||||
struct serial_device usb_serdev =
|
||||
{
|
||||
.open = usbdev_open,
|
||||
.close = usbdev_close,
|
||||
.send = usbdev_send,
|
||||
.recv = usbdev_recv,
|
||||
.drain = usbdev_drain,
|
||||
.flags = SERDEV_FL_NONE,
|
||||
};
|
||||
|
||||
/*
|
||||
* Device descriptor for the AVRISP mkII.
|
||||
*/
|
||||
struct serial_device usb_serdev_frame =
|
||||
{
|
||||
.open = usbdev_open,
|
||||
.close = usbdev_close,
|
||||
.send = usbdev_send,
|
||||
.recv = usbdev_recv_frame,
|
||||
.drain = usbdev_drain,
|
||||
.flags = SERDEV_FL_NONE,
|
||||
};
|
||||
|
||||
#endif /* HAVE_LIBUSB */
|
||||
1300
src/usbasp.c
Normal file
1300
src/usbasp.c
Normal file
File diff suppressed because it is too large
Load Diff
139
src/usbasp.h
Normal file
139
src/usbasp.h
Normal file
@@ -0,0 +1,139 @@
|
||||
/*
|
||||
* avrdude - A Downloader/Uploader for AVR device programmers
|
||||
* Copyright (C) 2006 Thomas Fischl
|
||||
*
|
||||
* 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/* $Id$ */
|
||||
|
||||
#ifndef usbasp_h
|
||||
#define usbasp_h
|
||||
|
||||
/* USB function call identifiers */
|
||||
#define USBASP_FUNC_CONNECT 1
|
||||
#define USBASP_FUNC_DISCONNECT 2
|
||||
#define USBASP_FUNC_TRANSMIT 3
|
||||
#define USBASP_FUNC_READFLASH 4
|
||||
#define USBASP_FUNC_ENABLEPROG 5
|
||||
#define USBASP_FUNC_WRITEFLASH 6
|
||||
#define USBASP_FUNC_READEEPROM 7
|
||||
#define USBASP_FUNC_WRITEEEPROM 8
|
||||
#define USBASP_FUNC_SETLONGADDRESS 9
|
||||
#define USBASP_FUNC_SETISPSCK 10
|
||||
#define USBASP_FUNC_TPI_CONNECT 11
|
||||
#define USBASP_FUNC_TPI_DISCONNECT 12
|
||||
#define USBASP_FUNC_TPI_RAWREAD 13
|
||||
#define USBASP_FUNC_TPI_RAWWRITE 14
|
||||
#define USBASP_FUNC_TPI_READBLOCK 15
|
||||
#define USBASP_FUNC_TPI_WRITEBLOCK 16
|
||||
#define USBASP_FUNC_GETCAPABILITIES 127
|
||||
|
||||
/* USBASP capabilities */
|
||||
#define USBASP_CAP_TPI 0x01
|
||||
#define USBASP_CAP_3MHZ (1 << 24) // 3 MHz SCK in UsbAsp-flash firmware
|
||||
|
||||
/* Block mode flags */
|
||||
#define USBASP_BLOCKFLAG_FIRST 1
|
||||
#define USBASP_BLOCKFLAG_LAST 2
|
||||
|
||||
/* Block mode data size */
|
||||
#define USBASP_READBLOCKSIZE 200
|
||||
#define USBASP_WRITEBLOCKSIZE 200
|
||||
|
||||
/* ISP SCK speed identifiers */
|
||||
#define USBASP_ISP_SCK_AUTO 0
|
||||
#define USBASP_ISP_SCK_0_5 1 /* 500 Hz */
|
||||
#define USBASP_ISP_SCK_1 2 /* 1 kHz */
|
||||
#define USBASP_ISP_SCK_2 3 /* 2 kHz */
|
||||
#define USBASP_ISP_SCK_4 4 /* 4 kHz */
|
||||
#define USBASP_ISP_SCK_8 5 /* 8 kHz */
|
||||
#define USBASP_ISP_SCK_16 6 /* 16 kHz */
|
||||
#define USBASP_ISP_SCK_32 7 /* 32 kHz */
|
||||
#define USBASP_ISP_SCK_93_75 8 /* 93.75 kHz */
|
||||
#define USBASP_ISP_SCK_187_5 9 /* 187.5 kHz */
|
||||
#define USBASP_ISP_SCK_375 10 /* 375 kHz */
|
||||
#define USBASP_ISP_SCK_750 11 /* 750 kHz */
|
||||
#define USBASP_ISP_SCK_1500 12 /* 1.5 MHz */
|
||||
#define USBASP_ISP_SCK_3000 13 /* 3 MHz only UsbAsp-flash firmware*/
|
||||
|
||||
/* TPI instructions */
|
||||
#define TPI_OP_SLD 0x20
|
||||
#define TPI_OP_SLD_INC 0x24
|
||||
#define TPI_OP_SST 0x60
|
||||
#define TPI_OP_SST_INC 0x64
|
||||
#define TPI_OP_SSTPR(a) (0x68 | (a))
|
||||
#define TPI_OP_SIN(a) (0x10 | (((a)<<1)&0x60) | ((a)&0x0F) )
|
||||
#define TPI_OP_SOUT(a) (0x90 | (((a)<<1)&0x60) | ((a)&0x0F) )
|
||||
#define TPI_OP_SLDCS(a) (0x80 | ((a)&0x0F) )
|
||||
#define TPI_OP_SSTCS(a) (0xC0 | ((a)&0x0F) )
|
||||
#define TPI_OP_SKEY 0xE0
|
||||
|
||||
/* TPI control/status registers */
|
||||
#define TPIIR 0xF
|
||||
#define TPIPCR 0x2
|
||||
#define TPISR 0x0
|
||||
|
||||
// TPIPCR bits
|
||||
#define TPIPCR_GT_2 0x04
|
||||
#define TPIPCR_GT_1 0x02
|
||||
#define TPIPCR_GT_0 0x01
|
||||
#define TPIPCR_GT_128b 0x00
|
||||
#define TPIPCR_GT_64b 0x01
|
||||
#define TPIPCR_GT_32b 0x02
|
||||
#define TPIPCR_GT_16b 0x03
|
||||
#define TPIPCR_GT_8b 0x04
|
||||
#define TPIPCR_GT_4b 0x05
|
||||
#define TPIPCR_GT_2b 0x06
|
||||
#define TPIPCR_GT_0b 0x07
|
||||
|
||||
// TPISR bits
|
||||
#define TPISR_NVMEN 0x02
|
||||
|
||||
/* NVM registers */
|
||||
#define NVMCSR 0x32
|
||||
#define NVMCMD 0x33
|
||||
|
||||
// NVMCSR bits
|
||||
#define NVMCSR_BSY 0x80
|
||||
|
||||
// NVMCMD values
|
||||
#define NVMCMD_NOP 0x00
|
||||
#define NVMCMD_CHIP_ERASE 0x10
|
||||
#define NVMCMD_SECTION_ERASE 0x14
|
||||
#define NVMCMD_WORD_WRITE 0x1D
|
||||
|
||||
|
||||
typedef struct sckoptions_t {
|
||||
int id;
|
||||
double frequency;
|
||||
} CLOCKOPTIONS;
|
||||
|
||||
/* USB error identifiers */
|
||||
#define USB_ERROR_NOTFOUND 1
|
||||
#define USB_ERROR_ACCESS 2
|
||||
#define USB_ERROR_IO 3
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
extern const char usbasp_desc[];
|
||||
void usbasp_initpgm (PROGRAMMER * pgm);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* usbasp_h */
|
||||
90
src/usbdevs.h
Normal file
90
src/usbdevs.h
Normal file
@@ -0,0 +1,90 @@
|
||||
/*
|
||||
* avrdude - A Downloader/Uploader for AVR device programmers
|
||||
* Copyright (C) 2006 Joerg Wunsch
|
||||
*
|
||||
* 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/* $Id$ */
|
||||
|
||||
/*
|
||||
* defines for the USB interface
|
||||
*/
|
||||
|
||||
#ifndef usbdevs_h
|
||||
#define usbdevs_h
|
||||
|
||||
#define USB_VENDOR_ATMEL 1003
|
||||
#define USB_DEVICE_JTAGICEMKII 0x2103
|
||||
#define USB_DEVICE_AVRISPMKII 0x2104
|
||||
#define USB_DEVICE_STK600 0x2106
|
||||
#define USB_DEVICE_AVRDRAGON 0x2107
|
||||
#define USB_DEVICE_JTAGICE3 0x2110
|
||||
#define USB_DEVICE_XPLAINEDPRO 0x2111
|
||||
#define USB_DEVICE_JTAG3_EDBG 0x2140
|
||||
#define USB_DEVICE_ATMEL_ICE 0x2141
|
||||
|
||||
#define USB_VENDOR_FTDI 0x0403
|
||||
#define USB_DEVICE_FT2232 0x6010
|
||||
#define USB_DEVICE_FT245 0x6001
|
||||
|
||||
#define USBASP_SHARED_VID 0x16C0 /* VOTI */
|
||||
#define USBASP_SHARED_PID 0x05DC /* Obdev's free shared PID */
|
||||
|
||||
#define USBASP_OLD_VID 0x03EB /* ATMEL */
|
||||
#define USBASP_OLD_PID 0xC7B4 /* (unoffical) USBasp */
|
||||
|
||||
#define USBASP_NIBOBEE_VID 0x16C0 /* VOTI */
|
||||
#define USBASP_NIBOBEE_PID 0x092F /* NIBObee PID */
|
||||
|
||||
// these are specifically assigned to USBtiny,
|
||||
// if you need your own VID and PIDs you can get them for cheap from
|
||||
// www.mecanique.co.uk so please don't reuse these. Thanks!
|
||||
#define USBTINY_VENDOR_DEFAULT 0x1781
|
||||
#define USBTINY_PRODUCT_DEFAULT 0x0C9F
|
||||
|
||||
|
||||
|
||||
/* JTAGICEmkII, AVRISPmkII */
|
||||
#define USBDEV_BULK_EP_WRITE_MKII 0x02
|
||||
#define USBDEV_BULK_EP_READ_MKII 0x82
|
||||
#define USBDEV_MAX_XFER_MKII 64
|
||||
|
||||
/* STK600 */
|
||||
#define USBDEV_BULK_EP_WRITE_STK600 0x02
|
||||
#define USBDEV_BULK_EP_READ_STK600 0x83
|
||||
|
||||
/* JTAGICE3 */
|
||||
#define USBDEV_BULK_EP_WRITE_3 0x01
|
||||
#define USBDEV_BULK_EP_READ_3 0x82
|
||||
#define USBDEV_EVT_EP_READ_3 0x83
|
||||
/*
|
||||
* The mk3 tools (type jtagice3) have a maxPayloadSize of 912. When
|
||||
* accessing paged memory the access should be limited to pageSize.
|
||||
* When accessing memory without pageSize the payload should be
|
||||
* limited to 256.
|
||||
*/
|
||||
#define USBDEV_MAX_XFER_3 912
|
||||
#define USBDEV_MAX_XFER_3_UNPAGED 256
|
||||
|
||||
/*
|
||||
* When operating on the JTAGICE3, usbdev_recv_frame() returns an
|
||||
* indication in the upper bits of the return value whether the
|
||||
* message has been received from the event endpoint rather than the
|
||||
* normal conversation endpoint.
|
||||
*/
|
||||
#define USB_RECV_LENGTH_MASK 0x0fff /* up to 4 KiB */
|
||||
#define USB_RECV_FLAG_EVENT 0x1000
|
||||
|
||||
#endif /* usbdevs_h */
|
||||
792
src/usbtiny.c
Normal file
792
src/usbtiny.c
Normal file
@@ -0,0 +1,792 @@
|
||||
/*
|
||||
* avrdude - A Downloader/Uploader for AVR device programmers
|
||||
* Copyright (C) 2007 Dick Streefland, adapted for 5.4 by Limor Fried
|
||||
*
|
||||
* 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Driver for "usbtiny"-type programmers
|
||||
* Please see http://www.xs4all.nl/~dicks/avr/usbtiny/
|
||||
* and http://www.ladyada.net/make/usbtinyisp/
|
||||
* For example schematics and detailed documentation
|
||||
*/
|
||||
|
||||
#include "ac_cfg.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <sys/time.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "avrdude.h"
|
||||
#include "libavrdude.h"
|
||||
|
||||
#include "usbtiny.h"
|
||||
#include "usbdevs.h"
|
||||
|
||||
#if defined(HAVE_LIBUSB) // we use LIBUSB to talk to the board
|
||||
#if defined(HAVE_USB_H)
|
||||
# include <usb.h>
|
||||
#elif defined(HAVE_LUSB0_USB_H)
|
||||
# include <lusb0_usb.h>
|
||||
#else
|
||||
# error "libusb needs either <usb.h> or <lusb0_usb.h>"
|
||||
#endif
|
||||
|
||||
#include "tpi.h"
|
||||
|
||||
#define TPIPCR_GT_0b 0x07
|
||||
#define TPI_STOP_BITS 0x03
|
||||
|
||||
#ifdef HAVE_NETINET_IN_H
|
||||
# include <netinet/in.h>
|
||||
# define LITTLE_TO_BIG_16(x) (htons(x))
|
||||
#else
|
||||
// WIN32
|
||||
# define LITTLE_TO_BIG_16(x) ((((x) << 8) & 0xFF00) | (((x) >> 8) & 0x00FF))
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_UINT_T
|
||||
typedef unsigned int uint_t;
|
||||
#endif
|
||||
#ifndef HAVE_ULONG_T
|
||||
typedef unsigned long ulong_t;
|
||||
#endif
|
||||
|
||||
extern int avr_write_byte_default ( PROGRAMMER* pgm, AVRPART* p,
|
||||
AVRMEM* mem, ulong_t addr,
|
||||
unsigned char data );
|
||||
/*
|
||||
* Private data for this programmer.
|
||||
*/
|
||||
struct pdata
|
||||
{
|
||||
usb_dev_handle *usb_handle;
|
||||
int sck_period;
|
||||
int chunk_size;
|
||||
int retries;
|
||||
};
|
||||
|
||||
#define PDATA(pgm) ((struct pdata *)(pgm->cookie))
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
static void usbtiny_setup(PROGRAMMER * pgm)
|
||||
{
|
||||
if ((pgm->cookie = malloc(sizeof(struct pdata))) == 0) {
|
||||
avrdude_message(MSG_INFO, "%s: usbtiny_setup(): Out of memory allocating private data\n",
|
||||
progname);
|
||||
exit(1);
|
||||
}
|
||||
memset(pgm->cookie, 0, sizeof(struct pdata));
|
||||
}
|
||||
|
||||
static void usbtiny_teardown(PROGRAMMER * pgm)
|
||||
{
|
||||
free(pgm->cookie);
|
||||
}
|
||||
|
||||
// Wrapper for simple usb_control_msg messages
|
||||
static int usb_control (PROGRAMMER * pgm,
|
||||
unsigned int requestid, unsigned int val, unsigned int index )
|
||||
{
|
||||
int nbytes;
|
||||
nbytes = usb_control_msg( PDATA(pgm)->usb_handle,
|
||||
USB_ENDPOINT_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
|
||||
requestid,
|
||||
val, index, // 2 bytes each of data
|
||||
NULL, 0, // no data buffer in control messge
|
||||
USB_TIMEOUT ); // default timeout
|
||||
if(nbytes < 0){
|
||||
avrdude_message(MSG_INFO, "\n%s: error: usbtiny_transmit: %s\n", progname, usb_strerror());
|
||||
return -1;
|
||||
}
|
||||
|
||||
return nbytes;
|
||||
}
|
||||
|
||||
// Wrapper for simple usb_control_msg messages to receive data from programmer
|
||||
static int usb_in (PROGRAMMER * pgm,
|
||||
unsigned int requestid, unsigned int val, unsigned int index,
|
||||
unsigned char* buffer, int buflen, int bitclk )
|
||||
{
|
||||
int nbytes;
|
||||
int timeout;
|
||||
int i;
|
||||
|
||||
// calculate the amout of time we expect the process to take by
|
||||
// figuring the bit-clock time and buffer size and adding to the standard USB timeout.
|
||||
timeout = USB_TIMEOUT + (buflen * bitclk) / 1000;
|
||||
|
||||
for (i = 0; i < 10; i++) {
|
||||
nbytes = usb_control_msg( PDATA(pgm)->usb_handle,
|
||||
USB_ENDPOINT_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
|
||||
requestid,
|
||||
val, index,
|
||||
(char *)buffer, buflen,
|
||||
timeout);
|
||||
if (nbytes == buflen) {
|
||||
return nbytes;
|
||||
}
|
||||
PDATA(pgm)->retries++;
|
||||
}
|
||||
avrdude_message(MSG_INFO, "\n%s: error: usbtiny_receive: %s (expected %d, got %d)\n",
|
||||
progname, usb_strerror(), buflen, nbytes);
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Report the number of retries, and reset the counter.
|
||||
static void check_retries (PROGRAMMER * pgm, const char* operation)
|
||||
{
|
||||
if (PDATA(pgm)->retries > 0 && quell_progress < 2) {
|
||||
avrdude_message(MSG_INFO, "%s: %d retries during %s\n", progname,
|
||||
PDATA(pgm)->retries, operation);
|
||||
}
|
||||
PDATA(pgm)->retries = 0;
|
||||
}
|
||||
|
||||
// Wrapper for simple usb_control_msg messages to send data to programmer
|
||||
static int usb_out (PROGRAMMER * pgm,
|
||||
unsigned int requestid, unsigned int val, unsigned int index,
|
||||
unsigned char* buffer, int buflen, int bitclk )
|
||||
{
|
||||
int nbytes;
|
||||
int timeout;
|
||||
|
||||
// calculate the amout of time we expect the process to take by
|
||||
// figuring the bit-clock time and buffer size and adding to the standard USB timeout.
|
||||
timeout = USB_TIMEOUT + (buflen * bitclk) / 1000;
|
||||
|
||||
nbytes = usb_control_msg( PDATA(pgm)->usb_handle,
|
||||
USB_ENDPOINT_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
|
||||
requestid,
|
||||
val, index,
|
||||
(char *)buffer, buflen,
|
||||
timeout);
|
||||
if (nbytes != buflen) {
|
||||
avrdude_message(MSG_INFO, "\n%s: error: usbtiny_send: %s (expected %d, got %d)\n",
|
||||
progname, usb_strerror(), buflen, nbytes);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return nbytes;
|
||||
}
|
||||
|
||||
/* Reverse the bits in a byte. Needed since TPI uses little-endian
|
||||
bit order (LSB first) whereas SPI uses big-endian (MSB first).*/
|
||||
static unsigned char reverse(unsigned char b) {
|
||||
return
|
||||
( (b & 0x01) << 7)
|
||||
| ((b & 0x02) << 5)
|
||||
| ((b & 0x04) << 3)
|
||||
| ((b & 0x08) << 1)
|
||||
| ((b & 0x10) >> 1)
|
||||
| ((b & 0x20) >> 3)
|
||||
| ((b & 0x40) >> 5)
|
||||
| ((b & 0x80) >> 7);
|
||||
}
|
||||
|
||||
/* Calculate even parity. */
|
||||
static unsigned char tpi_parity(unsigned char b)
|
||||
{
|
||||
unsigned char parity = 0;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < 8; ++i) {
|
||||
if (b & 1)
|
||||
parity ^= 1;
|
||||
b >>= 1;
|
||||
}
|
||||
return parity;
|
||||
}
|
||||
|
||||
/* Encode 1 start bit (0), 8 data bits, 1 parity, 2 stop bits (1)
|
||||
inside 16 bits. The data is padded to 16 bits by 4 leading 1s
|
||||
(which will be ignored since they're not start bits). This layout
|
||||
enables a write to be followed by a read. */
|
||||
static unsigned short tpi_frame(unsigned char b) {
|
||||
return LITTLE_TO_BIG_16(0xf000 |
|
||||
(reverse(b) << 3) |
|
||||
tpi_parity(b) << 2 |
|
||||
TPI_STOP_BITS);
|
||||
}
|
||||
|
||||
/* Transmit a single byte encapsulated in a 32-bit transfer. Unused
|
||||
bits are padded with 1s. */
|
||||
static int usbtiny_tpi_tx(PROGRAMMER *pgm, unsigned char b0)
|
||||
{
|
||||
unsigned char res[4];
|
||||
|
||||
if (usb_in(pgm, USBTINY_SPI, tpi_frame(b0), 0xffff,
|
||||
res, sizeof(res), 8 * sizeof(res) * PDATA(pgm)->sck_period) < 0)
|
||||
return -1;
|
||||
if (verbose > 1)
|
||||
fprintf(stderr, "CMD_TPI_TX: [0x%02x]\n", b0);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Transmit a two bytes encapsulated in a 32-bit transfer. Unused
|
||||
bits are padded with 1s. */
|
||||
static int usbtiny_tpi_txtx(PROGRAMMER *pgm,
|
||||
unsigned char b0, unsigned char b1)
|
||||
{
|
||||
unsigned char res[4];
|
||||
|
||||
if (usb_in(pgm, USBTINY_SPI, tpi_frame(b0), tpi_frame(b1),
|
||||
res, sizeof(res), 8 * sizeof(res) * PDATA(pgm)->sck_period) < 0)
|
||||
return -1;
|
||||
if (verbose > 1)
|
||||
fprintf(stderr, "CMD_TPI_TX_TX: [0x%02x 0x%02x]\n", b0, b1);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Transmit a byte then receive a byte, all encapsulated in a 32-bit
|
||||
transfer. Unused bits are padded with 1s. This code assumes that
|
||||
the start bit of the byte being received arrives within at most 2
|
||||
TPICLKs. We ensure this by calling avr_tpi_program_enable() with
|
||||
delay==TPIPCR_GT_0b. */
|
||||
static int usbtiny_tpi_txrx(PROGRAMMER *pgm, unsigned char b0)
|
||||
{
|
||||
unsigned char res[4], r;
|
||||
short w;
|
||||
|
||||
if (usb_in(pgm, USBTINY_SPI, tpi_frame(b0), 0xffff,
|
||||
res, sizeof(res), 8 * sizeof(res) * PDATA(pgm)->sck_period) < 0)
|
||||
return -1;
|
||||
|
||||
w = (res[2] << 8) | res[3];
|
||||
/* Look for start bit (there shoule be no more than two 1 bits): */
|
||||
while (w < 0)
|
||||
w <<= 1;
|
||||
/* Now that we found the start bit, the top 9 bits contain the start
|
||||
bit and the 8 data bits, but the latter in reverse order. */
|
||||
r = reverse(w >> 7);
|
||||
if (tpi_parity(r) != ((w >> 6) & 1)) {
|
||||
fprintf(stderr, "%s: parity bit is wrong\n", __func__);
|
||||
return -1;
|
||||
}
|
||||
if (((w >> 4) & 0x3) != TPI_STOP_BITS) {
|
||||
fprintf(stderr, "%s: stop bits not received correctly\n", __func__);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (verbose > 1)
|
||||
fprintf(stderr, "CMD_TPI_TX_RX: [0x%02x -> 0x%02x]\n", b0, r);
|
||||
return r;
|
||||
}
|
||||
|
||||
// Sometimes we just need to know the SPI command for the part to perform
|
||||
// a function. Here we wrap this request for an operation so that we
|
||||
// can just specify the part and operation and it'll do the right stuff
|
||||
// to get the information from AvrDude and send to the USBtiny
|
||||
static int usbtiny_avr_op (PROGRAMMER * pgm, AVRPART * p,
|
||||
int op,
|
||||
unsigned char *res)
|
||||
{
|
||||
unsigned char cmd[4];
|
||||
|
||||
if (p->op[op] == NULL) {
|
||||
avrdude_message(MSG_INFO, "Operation %d not defined for this chip!\n", op );
|
||||
return -1;
|
||||
}
|
||||
memset(cmd, 0, sizeof(cmd));
|
||||
avr_set_bits(p->op[op], cmd);
|
||||
|
||||
return pgm->cmd(pgm, cmd, res);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
/* Find a device with the correct VID/PID match for USBtiny */
|
||||
|
||||
static int usbtiny_open(PROGRAMMER* pgm, char* name)
|
||||
{
|
||||
struct usb_bus *bus;
|
||||
struct usb_device *dev = 0;
|
||||
char *bus_name = NULL;
|
||||
char *dev_name = NULL;
|
||||
int vid, pid;
|
||||
|
||||
// if no -P was given or '-P usb' was given
|
||||
if(strcmp(name, "usb") == 0)
|
||||
name = NULL;
|
||||
else {
|
||||
// calculate bus and device names from -P option
|
||||
const size_t usb_len = strlen("usb");
|
||||
if(strncmp(name, "usb", usb_len) == 0 && ':' == name[usb_len]) {
|
||||
bus_name = name + usb_len + 1;
|
||||
dev_name = strchr(bus_name, ':');
|
||||
if(NULL != dev_name)
|
||||
*dev_name++ = '\0';
|
||||
}
|
||||
}
|
||||
|
||||
usb_init(); // initialize the libusb system
|
||||
usb_find_busses(); // have libusb scan all the usb busses available
|
||||
usb_find_devices(); // have libusb scan all the usb devices available
|
||||
|
||||
PDATA(pgm)->usb_handle = NULL;
|
||||
|
||||
if (pgm->usbvid)
|
||||
vid = pgm->usbvid;
|
||||
else
|
||||
vid = USBTINY_VENDOR_DEFAULT;
|
||||
|
||||
LNODEID usbpid = lfirst(pgm->usbpid);
|
||||
if (usbpid) {
|
||||
pid = *(int *)(ldata(usbpid));
|
||||
if (lnext(usbpid))
|
||||
avrdude_message(MSG_INFO, "%s: Warning: using PID 0x%04x, ignoring remaining PIDs in list\n",
|
||||
progname, pid);
|
||||
} else {
|
||||
pid = USBTINY_PRODUCT_DEFAULT;
|
||||
}
|
||||
|
||||
|
||||
// now we iterate through all the busses and devices
|
||||
for ( bus = usb_busses; bus; bus = bus->next ) {
|
||||
for ( dev = bus->devices; dev; dev = dev->next ) {
|
||||
if (dev->descriptor.idVendor == vid
|
||||
&& dev->descriptor.idProduct == pid ) { // found match?
|
||||
avrdude_message(MSG_NOTICE, "%s: usbdev_open(): Found USBtinyISP, bus:device: %s:%s\n",
|
||||
progname, bus->dirname, dev->filename);
|
||||
// if -P was given, match device by device name and bus name
|
||||
if(name != NULL &&
|
||||
(NULL == dev_name ||
|
||||
strcmp(bus->dirname, bus_name) ||
|
||||
strcmp(dev->filename, dev_name)))
|
||||
continue;
|
||||
PDATA(pgm)->usb_handle = usb_open(dev); // attempt to connect to device
|
||||
|
||||
// wrong permissions or something?
|
||||
if (!PDATA(pgm)->usb_handle) {
|
||||
avrdude_message(MSG_INFO, "%s: Warning: cannot open USB device: %s\n",
|
||||
progname, usb_strerror());
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(NULL != name && NULL == dev_name) {
|
||||
avrdude_message(MSG_INFO, "%s: Error: Invalid -P value: '%s'\n", progname, name);
|
||||
avrdude_message(MSG_INFO, "%sUse -P usb:bus:device\n", progbuf);
|
||||
return -1;
|
||||
}
|
||||
if (!PDATA(pgm)->usb_handle) {
|
||||
avrdude_message(MSG_INFO, "%s: Error: Could not find USBtiny device (0x%x/0x%x)\n",
|
||||
progname, vid, pid );
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0; // If we got here, we must have found a good USB device
|
||||
}
|
||||
|
||||
/* Clean up the handle for the usbtiny */
|
||||
static void usbtiny_close ( PROGRAMMER* pgm )
|
||||
{
|
||||
if (! PDATA(pgm)->usb_handle) {
|
||||
return; // not a valid handle, bail!
|
||||
}
|
||||
usb_close(PDATA(pgm)->usb_handle); // ask libusb to clean up
|
||||
PDATA(pgm)->usb_handle = NULL;
|
||||
}
|
||||
|
||||
/* A simple calculator function determines the maximum size of data we can
|
||||
shove through a USB connection without getting errors */
|
||||
static void usbtiny_set_chunk_size (PROGRAMMER * pgm, int period)
|
||||
{
|
||||
PDATA(pgm)->chunk_size = CHUNK_SIZE; // start with the maximum (default)
|
||||
while (PDATA(pgm)->chunk_size > 8 && period > 16) {
|
||||
// Reduce the chunk size for a slow SCK to reduce
|
||||
// the maximum time of a single USB transfer.
|
||||
PDATA(pgm)->chunk_size >>= 1;
|
||||
period >>= 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Given a SCK bit-clock speed (in useconds) we verify its an OK speed and tell the
|
||||
USBtiny to update itself to the new frequency */
|
||||
static int usbtiny_set_sck_period (PROGRAMMER *pgm, double v)
|
||||
{
|
||||
PDATA(pgm)->sck_period = (int)(v * 1e6 + 0.5); // convert from us to 'int', the 0.5 is for rounding up
|
||||
|
||||
// Make sure its not 0, as that will confuse the usbtiny
|
||||
if (PDATA(pgm)->sck_period < SCK_MIN)
|
||||
PDATA(pgm)->sck_period = SCK_MIN;
|
||||
|
||||
// We can't go slower, due to the byte-size of the clock variable
|
||||
if (PDATA(pgm)->sck_period > SCK_MAX)
|
||||
PDATA(pgm)->sck_period = SCK_MAX;
|
||||
|
||||
avrdude_message(MSG_NOTICE, "%s: Setting SCK period to %d usec\n", progname,
|
||||
PDATA(pgm)->sck_period );
|
||||
|
||||
// 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)
|
||||
return -1;
|
||||
|
||||
// with the new speed, we'll have to update how much data we send per usb transfer
|
||||
usbtiny_set_chunk_size(pgm, PDATA(pgm)->sck_period);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int usbtiny_initialize (PROGRAMMER *pgm, AVRPART *p )
|
||||
{
|
||||
unsigned char res[4]; // store the response from usbtinyisp
|
||||
int tries;
|
||||
|
||||
// Check for bit-clock and tell the usbtiny to adjust itself
|
||||
if (pgm->bitclock > 0.0) {
|
||||
// -B option specified: convert to valid range for sck_period
|
||||
usbtiny_set_sck_period(pgm, pgm->bitclock);
|
||||
} else {
|
||||
// -B option not specified: use default
|
||||
PDATA(pgm)->sck_period = SCK_DEFAULT;
|
||||
avrdude_message(MSG_NOTICE, "%s: Using SCK period of %d usec\n",
|
||||
progname, PDATA(pgm)->sck_period );
|
||||
if (usb_control(pgm, USBTINY_POWERUP,
|
||||
PDATA(pgm)->sck_period, RESET_LOW ) < 0)
|
||||
return -1;
|
||||
usbtiny_set_chunk_size(pgm, PDATA(pgm)->sck_period);
|
||||
}
|
||||
|
||||
// Let the device wake up.
|
||||
usleep(50000);
|
||||
|
||||
if (p->flags & AVRPART_HAS_TPI) {
|
||||
/* Since there is a single TPIDATA line, MOSI and MISO must be
|
||||
linked together through a 1kOhm resistor. Verify that
|
||||
everything we send on MOSI gets mirrored back on MISO. */
|
||||
if (verbose >= 2)
|
||||
fprintf(stderr, "doing MOSI-MISO link check\n");
|
||||
|
||||
memset(res, 0xaa, sizeof(res));
|
||||
if (usb_in(pgm, USBTINY_SPI, LITTLE_TO_BIG_16(0x1234), LITTLE_TO_BIG_16(0x5678),
|
||||
res, 4, 32 * PDATA(pgm)->sck_period) < 0) {
|
||||
fprintf(stderr, "usb_in() failed\n");
|
||||
return -1;
|
||||
}
|
||||
if (res[0] != 0x12 || res[1] != 0x34 || res[2] != 0x56 || res[3] != 0x78) {
|
||||
fprintf(stderr,
|
||||
"MOSI->MISO check failed (got 0x%02x 0x%02x 0x%02x 0x%02x)\n"
|
||||
"\tPlease verify that MISO is connected directly to TPIDATA and\n"
|
||||
"\tMOSI is connected to TPIDATA through a 1kOhm resistor.\n",
|
||||
res[0], res[1], res[2], res[3]);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* keep TPIDATA high for >= 16 clock cycles: */
|
||||
if (usb_in(pgm, USBTINY_SPI, 0xffff, 0xffff, res, 4,
|
||||
32 * PDATA(pgm)->sck_period) < 0)
|
||||
{
|
||||
fprintf(stderr, "Unable to switch chip into TPI mode\n");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
for (tries = 0; tries < 4; ++tries) {
|
||||
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)
|
||||
return -1;
|
||||
usleep(50000);
|
||||
}
|
||||
if (tries >= 4)
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Tell the USBtiny to release the output pins, etc */
|
||||
static void usbtiny_powerdown(PROGRAMMER * pgm)
|
||||
{
|
||||
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
|
||||
}
|
||||
|
||||
/* Send a 4-byte SPI command to the USBtinyISP for execution
|
||||
This procedure is used by higher-level Avrdude procedures */
|
||||
static int usbtiny_cmd(PROGRAMMER * pgm, const unsigned char *cmd, unsigned char *res)
|
||||
{
|
||||
int nbytes;
|
||||
|
||||
// Make sure its empty so we don't read previous calls if it fails
|
||||
memset(res, '\0', 4 );
|
||||
|
||||
nbytes = usb_in( pgm, USBTINY_SPI,
|
||||
(cmd[1] << 8) | cmd[0], // convert to 16-bit words
|
||||
(cmd[3] << 8) | cmd[2], // "
|
||||
res, 4, 8 * PDATA(pgm)->sck_period );
|
||||
if (nbytes < 0)
|
||||
return -1;
|
||||
check_retries(pgm, "SPI command");
|
||||
// print out the data we sent and received
|
||||
avrdude_message(MSG_NOTICE2, "CMD: [%02x %02x %02x %02x] [%02x %02x %02x %02x]\n",
|
||||
cmd[0], cmd[1], cmd[2], cmd[3],
|
||||
res[0], res[1], res[2], res[3] );
|
||||
return ((nbytes == 4) && // should have read 4 bytes
|
||||
res[2] == cmd[1]); // AVR's do a delayed-echo thing
|
||||
}
|
||||
|
||||
int usbtiny_cmd_tpi(PROGRAMMER * pgm, const unsigned char *cmd,
|
||||
int cmd_len, unsigned char *res, int res_len)
|
||||
{
|
||||
unsigned char b0, b1;
|
||||
int tx, rx, r;
|
||||
|
||||
/* Transmits command two bytes at the time until we're down to 0 or
|
||||
1 command byte. Then we're either done or we transmit the final
|
||||
byte optionally followed by reading 1 byte. With the current TPI
|
||||
protocol, we never receive more than one byte. */
|
||||
for (tx = rx = 0; tx < cmd_len; ) {
|
||||
b0 = cmd[tx++];
|
||||
if (tx < cmd_len) {
|
||||
b1 = cmd[tx++];
|
||||
if (usbtiny_tpi_txtx(pgm, b0, b1) < 0)
|
||||
return -1;
|
||||
} else {
|
||||
if (res_len > 0) {
|
||||
if ((r = usbtiny_tpi_txrx(pgm, b0)) < 0)
|
||||
return -1;
|
||||
res[rx++] = r;
|
||||
} else {
|
||||
if (usbtiny_tpi_tx(pgm, b0) < 0)
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (rx < res_len) {
|
||||
fprintf(stderr, "%s: unexpected cmd_len=%d/res_len=%d\n",
|
||||
__func__, cmd_len, res_len);
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Send the chip-erase command */
|
||||
static int usbtiny_chip_erase(PROGRAMMER * pgm, AVRPART * p)
|
||||
{
|
||||
unsigned char res[4];
|
||||
|
||||
if (p->flags & AVRPART_HAS_TPI)
|
||||
return avr_tpi_chip_erase(pgm, p);
|
||||
|
||||
if (p->op[AVR_OP_CHIP_ERASE] == NULL) {
|
||||
avrdude_message(MSG_INFO, "Chip erase instruction not defined for part \"%s\"\n",
|
||||
p->desc);
|
||||
return -1;
|
||||
}
|
||||
|
||||
// get the command for erasing this chip and transmit to avrdude
|
||||
if (! usbtiny_avr_op( pgm, p, AVR_OP_CHIP_ERASE, res )) {
|
||||
return -1;
|
||||
}
|
||||
usleep( p->chip_erase_delay );
|
||||
|
||||
// prepare for further instruction
|
||||
pgm->initialize(pgm, p);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// These are required functions but don't actually do anything
|
||||
static void usbtiny_enable ( PROGRAMMER* pgm ) {}
|
||||
|
||||
static void usbtiny_disable ( PROGRAMMER* pgm ) {}
|
||||
|
||||
|
||||
/* To speed up programming and reading, we do a 'chunked' read.
|
||||
* We request just the data itself and the USBtiny uses the SPI function
|
||||
* given to read in the data. Much faster than sending a 4-byte SPI request
|
||||
* per byte
|
||||
*/
|
||||
static int usbtiny_paged_load (PROGRAMMER * pgm, AVRPART * p, AVRMEM* m,
|
||||
unsigned int page_size,
|
||||
unsigned int addr, unsigned int n_bytes)
|
||||
{
|
||||
unsigned int maxaddr = addr + n_bytes;
|
||||
int chunk;
|
||||
int function;
|
||||
|
||||
|
||||
// First determine what we're doing
|
||||
if (strcmp( m->desc, "flash" ) == 0) {
|
||||
function = USBTINY_FLASH_READ;
|
||||
} else {
|
||||
function = USBTINY_EEPROM_READ;
|
||||
}
|
||||
|
||||
for (; addr < maxaddr; addr += chunk) {
|
||||
chunk = PDATA(pgm)->chunk_size; // start with the maximum chunk size possible
|
||||
if (addr + chunk > maxaddr) {
|
||||
chunk = maxaddr - addr;
|
||||
}
|
||||
|
||||
// Send the chunk of data to the USBtiny with the function we want
|
||||
// to perform
|
||||
if (usb_in(pgm,
|
||||
function, // EEPROM or flash
|
||||
0, // delay between SPI commands
|
||||
addr, // address in memory
|
||||
m->buf + addr, // pointer to where we store data
|
||||
chunk, // number of bytes
|
||||
32 * PDATA(pgm)->sck_period) // each byte gets turned into a 4-byte SPI cmd
|
||||
< 0) {
|
||||
// usb_in() multiplies this per byte.
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
check_retries(pgm, "read");
|
||||
return n_bytes;
|
||||
}
|
||||
|
||||
/* To speed up programming and reading, we do a 'chunked' write.
|
||||
* We send just the data itself and the USBtiny uses the SPI function
|
||||
* given to write the data. Much faster than sending a 4-byte SPI request
|
||||
* per byte.
|
||||
*/
|
||||
static int usbtiny_paged_write(PROGRAMMER * pgm, AVRPART * p, AVRMEM * m,
|
||||
unsigned int page_size,
|
||||
unsigned int addr, unsigned int n_bytes)
|
||||
{
|
||||
unsigned int maxaddr = addr + n_bytes;
|
||||
int chunk; // Size of data to write at once
|
||||
int next;
|
||||
int function; // which SPI command to use
|
||||
int delay; // delay required between SPI commands
|
||||
|
||||
// First determine what we're doing
|
||||
if (strcmp( m->desc, "flash" ) == 0) {
|
||||
function = USBTINY_FLASH_WRITE;
|
||||
} else {
|
||||
function = USBTINY_EEPROM_WRITE;
|
||||
}
|
||||
|
||||
delay = 0;
|
||||
if (! m->paged) {
|
||||
unsigned int poll_value;
|
||||
// Does this chip not support paged writes?
|
||||
poll_value = (m->readback[1] << 8) | m->readback[0];
|
||||
if (usb_control(pgm, USBTINY_POLL_BYTES, poll_value, 0 ) < 0)
|
||||
return -1;
|
||||
delay = m->max_write_delay;
|
||||
}
|
||||
|
||||
for (; addr < maxaddr; addr += chunk) {
|
||||
// start with the max chunk size
|
||||
chunk = PDATA(pgm)->chunk_size;
|
||||
if (addr + chunk > maxaddr) {
|
||||
chunk = maxaddr - addr;
|
||||
}
|
||||
|
||||
// we can only write a page at a time anyways
|
||||
if (m->paged && chunk > page_size)
|
||||
chunk = page_size;
|
||||
|
||||
if (usb_out(pgm,
|
||||
function, // Flash or EEPROM
|
||||
delay, // How much to wait between each byte
|
||||
addr, // Address in memory
|
||||
m->buf + addr, // Pointer to data
|
||||
chunk, // Number of bytes to write
|
||||
32 * PDATA(pgm)->sck_period + delay // each byte gets turned into a
|
||||
// 4-byte SPI cmd usb_out() multiplies
|
||||
// this per byte. Then add the cmd-delay
|
||||
) < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
next = addr + chunk; // Calculate what address we're at now
|
||||
if (m->paged
|
||||
&& ((next % page_size) == 0 || next == maxaddr) ) {
|
||||
// If we're at a page boundary, send the SPI command to flush it.
|
||||
avr_write_page(pgm, p, m, (unsigned long) addr);
|
||||
}
|
||||
}
|
||||
return n_bytes;
|
||||
}
|
||||
|
||||
static int usbtiny_program_enable(PROGRAMMER *pgm, AVRPART *p)
|
||||
{
|
||||
unsigned char buf[4];
|
||||
|
||||
if (p->flags & AVRPART_HAS_TPI)
|
||||
return avr_tpi_program_enable(pgm, p, TPIPCR_GT_0b);
|
||||
else
|
||||
return usbtiny_avr_op(pgm, p, AVR_OP_PGM_ENABLE, buf);
|
||||
}
|
||||
|
||||
void usbtiny_initpgm ( PROGRAMMER* pgm )
|
||||
{
|
||||
strcpy(pgm->type, "USBtiny");
|
||||
|
||||
/* Mandatory Functions */
|
||||
pgm->initialize = usbtiny_initialize;
|
||||
pgm->enable = usbtiny_enable;
|
||||
pgm->disable = usbtiny_disable;
|
||||
pgm->program_enable = usbtiny_program_enable;
|
||||
pgm->chip_erase = usbtiny_chip_erase;
|
||||
pgm->cmd = usbtiny_cmd;
|
||||
pgm->cmd_tpi = usbtiny_cmd_tpi;
|
||||
pgm->open = usbtiny_open;
|
||||
pgm->close = usbtiny_close;
|
||||
pgm->read_byte = avr_read_byte_default;
|
||||
pgm->write_byte = avr_write_byte_default;
|
||||
|
||||
/* Optional Functions */
|
||||
pgm->powerup = NULL;
|
||||
pgm->powerdown = usbtiny_powerdown;
|
||||
pgm->paged_load = usbtiny_paged_load;
|
||||
pgm->paged_write = usbtiny_paged_write;
|
||||
pgm->set_sck_period = usbtiny_set_sck_period;
|
||||
pgm->setup = usbtiny_setup;
|
||||
pgm->teardown = usbtiny_teardown;
|
||||
}
|
||||
|
||||
#else /* !HAVE_LIBUSB */
|
||||
|
||||
// Give a proper error if we were not compiled with libusb
|
||||
|
||||
static int usbtiny_nousb_open(struct programmer_t *pgm, char * name)
|
||||
{
|
||||
avrdude_message(MSG_INFO, "%s: error: no usb support. Please compile again with libusb installed.\n",
|
||||
progname);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
void usbtiny_initpgm(PROGRAMMER * pgm)
|
||||
{
|
||||
strcpy(pgm->type, "usbtiny");
|
||||
|
||||
pgm->open = usbtiny_nousb_open;
|
||||
}
|
||||
|
||||
#endif /* HAVE_LIBUSB */
|
||||
|
||||
const char usbtiny_desc[] = "Driver for \"usbtiny\"-type programmers";
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user