Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/prusa3d/PrusaSlicer.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'src/avrdude/avr910.c')
-rw-r--r--src/avrdude/avr910.c777
1 files changed, 777 insertions, 0 deletions
diff --git a/src/avrdude/avr910.c b/src/avrdude/avr910.c
new file mode 100644
index 000000000..aa5cc07a9
--- /dev/null
+++ b/src/avrdude/avr910.c
@@ -0,0 +1,777 @@
+/*
+ * 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 <unistd.h>
+
+#if !defined(WIN32NATIVE)
+# include <sys/time.h>
+#endif
+
+#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.baud = pgm->baudrate;
+ 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;
+}