updated on Thu Jan 19 20:01:47 UTC 2012
[aur-mirror.git] / avrdude-serjtag / patch-serjtag.c.diff
blob9c86a46651ba762859e50e8e151959d79d57b937
1 --- /dev/null 2009-08-02 22:44:47.000000000 +0200
2 +++ serjtag.c 2009-08-02 21:56:45.000000000 +0200
3 @@ -0,0 +1,724 @@
4 +/*
5 + * avrdude - A Downloader/Uploader for AVR device programmers
6 + * Copyright (C) 2003-2004 Theodore A. Roth <troth@openavr.org>
7 + *
8 + * This program is free software; you can redistribute it and/or modify
9 + * it under the terms of the GNU General Public License as published by
10 + * the Free Software Foundation; either version 2 of the License, or
11 + * (at your option) any later version.
12 + *
13 + * This program is distributed in the hope that it will be useful,
14 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 + * GNU General Public License for more details.
17 + *
18 + * You should have received a copy of the GNU General Public License
19 + * along with this program; if not, write to the Free Software
20 + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 + */
23 +/* $Id$ */
25 +/* serjtag -- Serial Jtag Cable (using AVR) */
27 +#include "ac_cfg.h"
29 +#include <stdio.h>
30 +#include <stdlib.h>
31 +#include <string.h>
32 +#include <errno.h>
33 +#include <sys/time.h>
34 +#include <unistd.h>
36 +#include "avr.h"
37 +#include "pgm.h"
38 +#include "serjtag.h"
39 +#include "serial.h"
41 +#define SERJTAG_DEBUG 0
43 +extern char * progname;
44 +extern int do_cycles;
45 +extern int ovsigck;
46 +extern int verbose;
48 +static int serjtag_send(PROGRAMMER * pgm, char * buf, size_t len)
50 + return serial_send(&pgm->fd, (unsigned char *)buf, len);
54 +static int serjtag_recv(PROGRAMMER * pgm, char * buf, size_t len)
56 + int rv;
58 + rv = serial_recv(&pgm->fd, (unsigned char *)buf, len);
59 + if (rv < 0) {
60 + fprintf(stderr,
61 + "%s: serjtag_recv(): programmer is not responding\n",
62 + progname);
63 + exit(1);
64 + }
65 + return 0;
69 +static int serjtag_drain(PROGRAMMER * pgm, int display)
71 + return serial_drain(&pgm->fd, display);
74 +static int serjtag_chip_erase(PROGRAMMER * pgm, AVRPART * p)
76 + unsigned char cmd[4];
77 + unsigned char res[4];
79 + if (p->op[AVR_OP_CHIP_ERASE] == NULL) {
80 + fprintf(stderr, "chip erase instruction not defined for part \"%s\"\n",
81 + p->desc);
82 + return -1;
83 + }
85 + memset(cmd, 0, sizeof(cmd));
87 + avr_set_bits(p->op[AVR_OP_CHIP_ERASE], cmd);
88 + pgm->cmd(pgm, cmd, res);
89 + usleep(p->chip_erase_delay);
90 + pgm->initialize(pgm, p);
92 + return 0;
95 +#if SERJTAG_DEBUG == 1
96 +static void serjtag_check(PROGRAMMER * pgm) {
97 + int i,bytes;
98 + char buf[128];
100 +fprintf(stderr,"check response\n");
101 +fflush(stderr);
102 + i=0;
103 + buf[i++] = 'r';
104 + buf[i++] = 0;
105 + buf[i++] = 0;
106 + serjtag_send(pgm, buf, i);
107 + serjtag_recv(pgm, buf, 1);
108 +fprintf(stderr,"\tCommonad = 0x%02x %c\n",buf[0],buf[0]);
109 + serjtag_recv(pgm, buf+1, 1);
110 +fprintf(stderr,"\tFlags = 0x%02x\n",buf[1]);
111 + serjtag_recv(pgm, buf+2, 1);
112 +fprintf(stderr,"\tBytes = 0x%02x\n",buf[2]);
113 + bytes = buf[2];
114 + if (buf[1] & JTAG_BITS) bytes++;
115 + if (bytes) {
116 + fprintf(stderr,"\t");
117 + for (i=0; i<bytes; i++) {
118 + serjtag_recv(pgm, buf+2+i, 1);
119 + fprintf(stderr,"%02x ",buf[2+i]);
121 + fprintf(stderr,"\n");
124 +#endif
126 +static int serjtag_recv_j(PROGRAMMER * pgm, char * buf, size_t len, int verbose)
128 + int bytes;
129 + serjtag_recv(pgm, buf, 3); /* header */
130 +#if 0
131 + if (verbose) {
132 + fprintf(stderr,"recv_j(0) %c 0x%02x %d :",buf[0],buf[1],buf[2]);
134 +#endif
135 + bytes = buf[2];
136 + if (buf[1] & JTAG_BITS) {
137 + bytes++;
139 + len -= 3;
140 + if (len >= bytes) {
141 + serjtag_recv(pgm, buf+3, bytes);
142 + } else {
143 + char tmp[1];
144 + int i;
145 + serjtag_recv(pgm, buf+3, len);
146 + for (i=0; i< bytes - len; i++) {
147 + serjtag_recv(pgm, tmp, 1);
150 + if (verbose) {
151 + int i;
152 + fprintf(stderr,"recv_j %c 0x%02x %d :",buf[0],buf[1],buf[2]);
153 + for (i=0; i<bytes; i++) {
154 + fprintf(stderr,"%02x ",buf[3+i]&0xff);
156 + fprintf(stderr,"\n");
158 + return 0;
161 +static int delay_param = 3;
162 +static int use_delay = JTAG_USE_DELAY;
163 +static unsigned char saved_signature[3];
165 +static void serjtag_set_delay(PROGRAMMER * pgm) {
166 + use_delay = JTAG_USE_DELAY;
167 + if (pgm->bitclock == 0.0) { // using default
168 + delay_param = 3;
169 + } else if (pgm->bitclock >= 4.0) {
170 + delay_param = 0;
171 + use_delay = 0;
172 + } else {
173 + delay_param = (int)((2.26/3.0) / pgm->bitclock);
174 + if (delay_param > 15) delay_param = 15;
176 + if ((verbose>=1) || SERJTAG_DEBUG) {
177 + fprintf(stderr," serjtag:delay %d (%s) ( bitclk %.3f )\n"
178 + ,delay_param, use_delay? "enabled":"disabled", pgm->bitclock);
183 + * issue the 'program enable' command to the AVR device
184 + */
185 +static int serjtag_program_enable(PROGRAMMER * pgm, AVRPART * p)
187 + char buf[128];
188 + int i;
189 + int retry_count = 0;
191 + serjtag_set_delay(pgm);
193 + serjtag_send(pgm, "j", 1); // enter jtag mode
194 + serjtag_recv(pgm, buf, 1);
195 + if (buf[0] != 'Y') {
196 + return -1;
198 +#if SERJTAG_DEBUG == 1
199 +fprintf(stderr," Enter jtag mode .. success \n");
200 +#endif
202 +retry:
203 + i=0;
204 + buf[i++] = 's'; /* Set Port */
205 + buf[i++] = 0; /* flags */
206 + buf[i++] = 1; /* bytes */
207 + buf[i++] = 0; /* TDI(MOSI) = 0, TMS(RESET) = 0, TCK(SCK) = 0 */
208 + serjtag_send(pgm, buf, i);
209 + usleep(5000); // 5ms
210 + i=0;
211 + buf[i++] = 's'; /* Set Port */
212 + buf[i++] = 0; /* flags */
213 + buf[i++] = 1; /* bytes */
214 + buf[i++] = JTAG_SET_TMS; /* TDI(MOSI) = 0, TMS(RESET) = 1, TCK(SCK) = 0 */
215 + serjtag_send(pgm, buf, i);
216 + usleep(5000); // 5ms
217 + i=0;
218 + buf[i++] = 's'; /* Set Port */
219 + buf[i++] = 0; /* flags */
220 + buf[i++] = 1; /* bytes */
221 + buf[i++] = delay_param & JTAG_SET_DELAY; /* TMS(RESET) = 0, set delay */
222 + serjtag_send(pgm, buf, i);
223 + usleep(5000); // 5ms
225 + i = 0;
226 + buf[i++] = 'd'; /* PUT TDI Stream */
227 + buf[i++] = JTAG_RECIEVE | JTAG_USE_DELAY;
228 + buf[i++] = 0; /* bytes : set after*/
229 + /* check */
230 + buf[i++] = 0xAC;
231 + buf[i++] = 0x53;
232 + buf[i++] = 0;
233 + buf[i++] = 0;
234 + /* signature[0] */
235 + buf[i++] = 0x30;
236 + buf[i++] = 0;
237 + buf[i++] = 0;
238 + buf[i++] = 0;
239 + /* signature[1] */
240 + buf[i++] = 0x30;
241 + buf[i++] = 0;
242 + buf[i++] = 1;
243 + buf[i++] = 0;
244 + /* signature[2] */
245 + buf[i++] = 0x30;
246 + buf[i++] = 0;
247 + buf[i++] = 2;
248 + buf[i++] = 0;
249 + buf[2] = i - 3; /* set bytes */
250 + buf[i++] = 'r'; /* Request Recieved Data */
251 + buf[i++] = 0; /* flags */
252 + buf[i++] = 0; /* bytes */
253 + serjtag_send(pgm, buf, i);
254 +#if SERJTAG_DEBUG == 1
255 + fprintf(stderr,"enabling program delay %d retry %d\n",delay_param,retry_count);
256 +#endif
257 + serjtag_recv_j(pgm, buf, 3+4*4, SERJTAG_DEBUG?1:0);
259 + saved_signature[0] = buf[3+4*1 +3];
260 + saved_signature[1] = buf[3+4*2 +3];
261 + saved_signature[2] = buf[3+4*3 +3];
262 +#if SERJTAG_DEBUG == 1
263 + fprintf(stderr,"saved_signature %02x %02x %02x\n"
264 + , saved_signature[0]
265 + , saved_signature[1]
266 + , saved_signature[2]);
267 +#endif
268 + if ((buf[3+2] == 0x53) && (saved_signature[0] == 0x1e)) // success
270 + return 0;
272 + if (retry_count < 5) {
273 + retry_count++;
274 + goto retry;
276 + return -1;
279 +static int serjtag_read_sig_bytes(PROGRAMMER * pgm, AVRPART * p, AVRMEM * m)
281 + m->buf[0] = saved_signature[0];
282 + m->buf[1] = saved_signature[1];
283 + m->buf[2] = saved_signature[2];
284 + return 3;
288 + * initialize the AVR device and prepare it to accept commands
289 + */
290 +static int serjtag_initialize(PROGRAMMER * pgm, AVRPART * p)
292 + char id[8];
293 + char sw[3];
295 + /* Get the programmer identifier. Programmer returns exactly 7 chars
296 + _without_ the null.*/
298 + serjtag_send(pgm, "S", 1);
299 + serjtag_recv(pgm, id, 7);
300 + id[7] = 0;
302 + /* Get the HW and SW versions to see if the programmer is present. */
304 + serjtag_send(pgm, "V", 1);
305 + serjtag_recv(pgm, sw, 2);
306 + sw[2] = 0;
308 + fprintf(stderr, "Found programmer: Id = \"%s\"; Revison = %s\n", id, sw);
310 + if (strncmp(id, "SERJTAG", 7) && strncmp(id, "USB910A", 7)
311 + && strncmp(id, "USB910A", 7) )
313 + fprintf(stderr, "\tserjtag protocol not supported.\n");
314 + exit(1);
316 + return serjtag_program_enable(pgm, p);
319 +static void serjtag_disable(PROGRAMMER * pgm)
321 + char buf[2];
322 + serjtag_send(pgm, "V", 1);
323 + serjtag_recv(pgm, buf, 2);
325 + return;
329 +static void serjtag_enable(PROGRAMMER * pgm)
331 + /* Do nothing. */
333 + return;
338 + * transmit an AVR device command and return the results; 'cmd' and
339 + * 'res' must point to at least a 4 byte data buffer
340 + */
341 +static int serjtag_cmd(PROGRAMMER * pgm, unsigned char cmd[4],
342 + unsigned char res[4])
344 + char buf[10];
346 + /* FIXME: Insert version check here */
348 + buf[0] = 'd'; /* PUT TDI Stream */
349 + buf[1] = JTAG_RECIEVE | use_delay;
350 + buf[2] = 4; /* bytes */
351 + buf[3] = cmd[0];
352 + buf[4] = cmd[1];
353 + buf[5] = cmd[2];
354 + buf[6] = cmd[3];
355 + buf[7] = 'r'; /* Request Recieved Data */
356 + buf[8] = 0;
357 + buf[9] = 0;
359 + serjtag_send (pgm, buf, 10);
360 + serjtag_recv (pgm, buf, 7);
362 + res[0] = 0x00; /* Dummy value */
363 + res[1] = cmd[0];
364 + res[2] = cmd[1];
365 + res[3] = buf[6];
367 + return 0;
371 +static int serjtag_open(PROGRAMMER * pgm, char * port)
373 + /*
374 + * If baudrate was not specified use 19.200 Baud
375 + */
376 + if(pgm->baudrate == 0) {
377 + pgm->baudrate = 19200;
380 + strcpy(pgm->port, port);
381 + serial_open(port, pgm->baudrate, &pgm->fd);
383 + /*
384 + * drain any extraneous input
385 + */
386 + serjtag_drain (pgm, 0);
388 + return 0;
391 +static void serjtag_close(PROGRAMMER * pgm)
393 + serial_close(&pgm->fd);
394 + pgm->fd.ifd = -1;
398 +static void serjtag_display(PROGRAMMER * pgm, char * p)
400 + return;
403 +static int serjtag_paged_write_gen(PROGRAMMER * pgm, AVRPART * p,
404 + AVRMEM * m, int page_size, int n_bytes)
406 + unsigned long i;
407 + int rc;
408 + for (i=0; i<n_bytes; i++) {
409 + report_progress(i, n_bytes, NULL);
411 + rc = avr_write_byte_default(pgm, p, m, i, m->buf[i]);
412 + if (rc != 0) {
413 + return -2;
416 + if (m->paged) {
417 + /*
418 + * check to see if it is time to flush the page with a page
419 + * write
420 + */
421 + if (((i % m->page_size) == m->page_size-1) || (i == n_bytes-1)) {
422 + rc = avr_write_page(pgm, p, m, i);
423 + if (rc != 0) {
424 + return -2;
429 + return i;
432 +#define SERJTAG_BUFFERD_WRITE
434 +#ifdef SERJTAG_BUFFERD_WRITE
435 +#define SERJTAG_BUF_SIZE 1024
436 +unsigned char *serjtag_buf;
437 +int serjtag_buf_len;
439 +static void serjtag_flush(PROGRAMMER * pgm) {
440 + if (!serjtag_buf || (serjtag_buf_len == 0)) return;
441 + serjtag_send(pgm, serjtag_buf, serjtag_buf_len);
442 + serjtag_buf_len = 0;
445 +static void serjtag_write(PROGRAMMER * pgm, unsigned char *buf, int size) {
446 + if (!serjtag_buf) {
447 + serjtag_buf = malloc(SERJTAG_BUF_SIZE);
448 + if (!serjtag_buf) {
449 + fprintf(stderr, "can't alloc memory\n");
450 + exit(1);
453 + if (SERJTAG_BUF_SIZE < serjtag_buf_len + size) {
454 + serjtag_flush(pgm);
456 + memcpy(serjtag_buf + serjtag_buf_len, buf, size);
457 + serjtag_buf_len += size;
459 +#else
460 +static void serjtag_flush(PROGRAMMER * pgm) {
462 +static void serjtag_write(PROGRAMMER * pgm, unsigned char *buf, int size) {
463 + serjtag_send(pgm, buf, size);
465 +#endif
467 +#define USE_INLINE_WRITE_PAGE
469 +static int serjtag_paged_write_flash(PROGRAMMER * pgm, AVRPART * p, AVRMEM * m,
470 + int page_size, int n_bytes)
472 + unsigned int i,j;
473 + int addr,addr_save,buf_pos,do_page_write;
474 + char buf[128];
476 + addr = 0;
477 + for (i=0; i<n_bytes; ) {
478 + addr_save = addr;
479 + buf_pos = 0;
480 + buf[buf_pos++] = 'd'; /* PUT TDI Stream */
481 + buf[buf_pos++] = use_delay;
482 + buf[buf_pos++] = 0; /* bytes : set after */
483 + do_page_write = 0;
484 + for (j=0; j<(JTAG_BUFSIZE-3)/4; j++) { // 15 bytes
485 + buf[buf_pos++] = (addr & 1)?0x48:0x40;
486 + buf[buf_pos++] = (addr >> 9) & 0xff;
487 + buf[buf_pos++] = (addr >> 1) & 0xff;
488 + buf[buf_pos++] = m->buf[i];
489 + addr ++;
490 + i++;
491 + if ( (m->paged) &&
492 + (((i % m->page_size) == 0) || (i == n_bytes))) {
493 + do_page_write = 1;
494 + break;
497 + buf[2] = buf_pos - 3;
498 +#ifdef USE_INLINE_WRITE_PAGE
499 + if (do_page_write) {
500 + int addr_wk = addr_save - (addr_save % m->page_size);
501 + /* If this device has a "load extended address" command, issue it. */
502 + if (m->op[AVR_OP_LOAD_EXT_ADDR]) {
503 + OPCODE *lext = m->op[AVR_OP_LOAD_EXT_ADDR];
505 + buf[buf_pos++] = 'd'; /* PUT TDI Stream */
506 + buf[buf_pos++] = JTAG_RECIEVE | use_delay;
507 + buf[buf_pos++] = 4; /* bytes */
509 + memset(buf+buf_pos, 0, 4);
510 + avr_set_bits(lext, buf+buf_pos);
511 + avr_set_addr(lext, buf+buf_pos, addr/2);
512 + buf_pos += 4;
514 + buf[buf_pos++] = 'd'; /* PUT TDI Stream */
515 + buf[buf_pos++] = JTAG_RECIEVE | use_delay;
516 + buf[buf_pos++] = 4; /* bytes */
517 + buf[buf_pos++] = 0x4C; /* Issue Page Write */
518 + buf[buf_pos++] = (addr_wk >> 9) & 0xff;
519 + buf[buf_pos++] = (addr_wk >> 1) & 0xff;
520 + buf[buf_pos++] = 0;
521 + buf[buf_pos++] = 'r'; /* Request Recieved Data */
522 + buf[buf_pos++] = 0;
523 + buf[buf_pos++] = 0;
525 +#endif
526 + serjtag_write(pgm, buf, buf_pos);
527 +#if 0
528 +fprintf(stderr, "send addr 0x%04x size %d bufsize %d i %d page_write %d\n",
529 + addr_wk,buf[2],buf_pos,i,do_page_write);
530 +#endif
531 + if (do_page_write) {
532 +#ifdef USE_INLINE_WRITE_PAGE
533 + serjtag_flush(pgm);
534 + usleep(m->max_write_delay);
535 + serjtag_recv_j(pgm, buf, 4 + 3, 0);
536 +#else
537 + int rc;
538 + serjtag_flush(pgm);
539 + addr_wk = (i-1) / m->page_size * m->page_size;
540 + rc = avr_write_page(pgm, p, m, addr_wk);
541 + if (rc != 0) {
542 + return -2;
544 +#endif
546 + report_progress(i, n_bytes, NULL);
548 + serjtag_flush(pgm);
549 + return i;
553 +static int serjtag_paged_write(PROGRAMMER * pgm, AVRPART * p, AVRMEM * m,
554 + int page_size, int n_bytes)
556 + if (strcmp(m->desc, "flash") == 0) {
557 + return serjtag_paged_write_flash(pgm, p, m, page_size, n_bytes);
559 + else if (strcmp(m->desc, "eeprom") == 0) {
560 + return serjtag_paged_write_gen(pgm, p, m, page_size, n_bytes);
562 + else {
563 + return -2;
568 +static int serjtag_paged_load_gen(PROGRAMMER * pgm, AVRPART * p, AVRMEM * m,
569 + int page_size, int n_bytes)
571 + unsigned char rbyte;
572 + unsigned long i;
573 + int rc;
575 + for (i=0; i<n_bytes; i++) {
576 + rc = avr_read_byte_default(pgm, p, m, i, &rbyte);
577 + if (rc != 0) {
578 + return -2;
580 + m->buf[i] = rbyte;
581 + report_progress(i, n_bytes, NULL);
583 + return 0;
587 +static struct serjtag_request {
588 + int addr;
589 + int bytes;
590 + int n;
591 + struct serjtag_request *next;
592 +} *req_head,*req_tail,*req_pool;
594 +static void put_request(int addr, int bytes, int n)
596 + struct serjtag_request *p;
597 + if (req_pool) {
598 + p = req_pool;
599 + req_pool = p->next;
600 + } else {
601 + p = malloc(sizeof(struct serjtag_request));
602 + if (!p) {
603 + fprintf(stderr, "can't alloc memory\n");
604 + exit(1);
607 + memset(p, 0, sizeof(struct serjtag_request));
608 + p->addr = addr;
609 + p->bytes = bytes;
610 + p->n = n;
611 + if (req_tail) {
612 + req_tail->next = p;
613 + req_tail = p;
614 + } else {
615 + req_head = req_tail = p;
619 +static int do_request(PROGRAMMER * pgm, AVRMEM *m)
621 + struct serjtag_request *p;
622 + int addr, bytes, j, n;
623 + char buf[128];
625 + if (!req_head) return 0;
626 + p = req_head;
627 + req_head = p->next;
628 + if (!req_head) req_tail = req_head;
630 + addr = p->addr;
631 + bytes = p->bytes;
632 + n = p->n;
633 + memset(p, 0, sizeof(struct serjtag_request));
634 + p->next = req_pool;
635 + req_pool = p;
637 + serjtag_recv_j(pgm, buf, bytes + 3, 0);
638 + for (j=0; j<n; j++) {
639 + m->buf[addr++] = buf[3 + 4*j + 3];
641 + return 1;
644 +#define REQ_OUTSTANDINGS 10
645 +static int serjtag_paged_load_flash(PROGRAMMER * pgm, AVRPART * p, AVRMEM * m,
646 + int page_size, int n_bytes)
648 + unsigned long i,j,n;
649 + //int rc;
650 + int addr,addr_save,bytes,buf_pos;
651 + int req_count = 0;
652 + char buf[128];
654 + addr = 0;
655 + for (i=0; i<n_bytes; ) {
656 + buf_pos = 0;
657 + buf[buf_pos++] = 'd'; /* PUT TDI Stream */
658 + buf[buf_pos++] = JTAG_RECIEVE | use_delay;
659 + buf[buf_pos++] = 0; /* bytes : set after */
660 + addr_save = addr;
661 + for (j=0; j<(JTAG_BUFSIZE-3*2)/4; j++) { // 14 bytes
662 + if (i >= n_bytes) break;
663 + buf[buf_pos++] = (addr & 1)?0x28:0x20;
664 + buf[buf_pos++] = (addr >> 9) & 0xff;
665 + buf[buf_pos++] = (addr >> 1) & 0xff;
666 + buf[buf_pos++] = 0;
667 + addr ++;
668 + i++;
670 + n = j;
671 + buf[2] = bytes = buf_pos - 3;
672 + buf[buf_pos++] = 'r'; /* Request Recieved Data */
673 + buf[buf_pos++] = 0;
674 + buf[buf_pos++] = 0;
675 + serjtag_send(pgm, buf, buf_pos);
676 + put_request(addr_save, bytes, n);
677 + req_count++;
678 + if (req_count > REQ_OUTSTANDINGS)
679 + do_request(pgm, m);
680 + report_progress(i, n_bytes, NULL);
682 + while (do_request(pgm, m))
684 + return 0;
687 +static int serjtag_paged_load(PROGRAMMER * pgm, AVRPART * p, AVRMEM * m,
688 + int page_size, int n_bytes)
690 + if (strcmp(m->desc, "flash") == 0) {
691 + return serjtag_paged_load_flash(pgm, p, m, page_size, n_bytes);
693 + else if (strcmp(m->desc, "eeprom") == 0) {
694 + return serjtag_paged_load_gen(pgm, p, m, page_size, n_bytes);
696 + else {
697 + return -2;
701 +void serjtag_initpgm(PROGRAMMER * pgm)
703 + strcpy(pgm->type, "serjtag");
705 + /*
706 + * mandatory functions
707 + */
708 + pgm->initialize = serjtag_initialize;
709 + pgm->display = serjtag_display;
710 + pgm->enable = serjtag_enable;
711 + pgm->disable = serjtag_disable;
712 + pgm->program_enable = serjtag_program_enable;
713 + pgm->chip_erase = serjtag_chip_erase;
714 + pgm->cmd = serjtag_cmd;
715 + pgm->open = serjtag_open;
716 + pgm->close = serjtag_close;
717 + pgm->read_byte = avr_read_byte_default;
718 + pgm->write_byte = avr_write_byte_default;
720 + /*
721 + * optional functions
722 + */
724 + pgm->paged_write = serjtag_paged_write;
725 + pgm->paged_load = serjtag_paged_load;
726 + pgm->read_sig_bytes = serjtag_read_sig_bytes;