In lieu of Michael Holzt, add his serbb serial bit-bang code so it

will be available in the upcoming avrdude release.

His addition has been implemented by means of a generalized bit-bang
interface that contains the common part between serial and paralle
bit-bang devices, and specialed backends for the serial and parallel
port connections.


git-svn-id: svn://svn.savannah.nongnu.org/avrdude/trunk/avrdude@515 81a1dc3b-b13d-400b-aceb-764788c761c2
This commit is contained in:
Joerg Wunsch 2005-09-18 20:12:23 +00:00
parent 8ea8105786
commit 5c8f87e395
16 changed files with 1130 additions and 302 deletions

View File

@ -1,3 +1,23 @@
2005-09-18 Joerg Wunsch <j@uriah.heep.sax.de>
Add the serial bit-bang driver, contributed by Michael Holzt.
* bitbang.h: New file.
* bitbang.c: New file.
* serbb.h: New file.
* serbb_posix.c: New file.
* serbb_win32.c: New file.
* Makefile.am: Include new files.
* config_gram.y: Add serbb to configuration language.
* lexer.l: (Ditto.)
* par.c: Centralize bit-bang code in bitbang.c.
* par.h: Declare newly published functions.
* pgm.h (struct programmer_t): Add a flag field for private use
by the programmer.
* pindefs.h: Add definitions for negated serbb pins.
* avrdude.conf.in: Add serbb programmers ponyser, dasa, and dasa3.
* avrdude.1: Document serbb code.
* doc/avrdude.texi: (Ditto.)
2005/09/18 Brian S. Dean <bsd@bsdhome.com> 2005/09/18 Brian S. Dean <bsd@bsdhome.com>
* avrdude.conf.in: Patch #4078: add VCC pin definition for DAPA * avrdude.conf.in: Patch #4078: add VCC pin definition for DAPA

View File

@ -57,6 +57,8 @@ avrdude_SOURCES = \
avr910.h \ avr910.h \
avrpart.c \ avrpart.c \
avrpart.h \ avrpart.h \
bitbang.c \
bitbang.h \
butterfly.c \ butterfly.c \
butterfly.h \ butterfly.h \
config.c \ config.c \
@ -85,6 +87,9 @@ avrdude_SOURCES = \
safemode.c \ safemode.c \
safemode.h \ safemode.h \
serial.h \ serial.h \
serbb.h \
serbb_posix.c \
serbb_win32.c \
ser_posix.c \ ser_posix.c \
ser_win32.c \ ser_win32.c \
stk500.c \ stk500.c \

3
NEWS
View File

@ -21,6 +21,9 @@ Current:
- ATmega329x/649x - ATmega329x/649x
- ATtiny25/45/85 - ATtiny25/45/85
* Support for serial bit-bang adapters: Ponyprog serial, UISP DASA,
UISP DASA3.
* DAPA programmer pinout supported * DAPA programmer pinout supported
* New "safemode" feature where fuse bits are verified before exit * New "safemode" feature where fuse bits are verified before exit

View File

@ -19,7 +19,7 @@
.\" .\"
.\" $Id$ .\" $Id$
.\" .\"
.Dd DATE August 28, 2005 .Dd DATE September 18, 2005
.Os .Os
.Dt AVRDUDE 1 .Dt AVRDUDE 1
.Sh NAME .Sh NAME
@ -61,7 +61,8 @@ programmer connected directly to a
.Xr ppi 4 .Xr ppi 4
or or
.Xr parport 4 .Xr parport 4
parallel port. In the simplest case, the hardware consists just of a parallel port, or to a standard serial port.
In the simplest case, the hardware consists just of a
cable connecting the respective AVR signal lines to the parallel port. cable connecting the respective AVR signal lines to the parallel port.
.Pp .Pp
The MCU is programmed in The MCU is programmed in
@ -83,6 +84,15 @@ signal is available to control a buffer/driver IC 74LS367 (or
74HCT367). The latter can be useful to decouple the parallel port 74HCT367). The latter can be useful to decouple the parallel port
from the MCU when in-system programming is used. from the MCU when in-system programming is used.
.Pp .Pp
A number of equally simple bit-bang programming adapters that connect
to a serial port are supported as well, among them the popular
Ponyprog serial adapter, and the DASA and DASA3 adapters that used to
be supported by uisp(1).
Note that these adapters are meant to be attached to a physical serial
port.
Connecting to a serial port emulated on top of USB is likely to not
work at all, or to work abysmally slow.
.Pp
Atmel's STK500 programmer is also supported and connects to a serial Atmel's STK500 programmer is also supported and connects to a serial
port. port.
Both, firmware versions 1.x and 2.x can be handled, but require a Both, firmware versions 1.x and 2.x can be handled, but require a

280
bitbang.c Normal file
View File

@ -0,0 +1,280 @@
/*
* avrdude - A Downloader/Uploader for AVR device programmers
* Copyright (C) 2000, 2001, 2002, 2003 Brian S. Dean <bsd@bsdhome.com>
* Copyright (C) 2005 Michael Holzt <kju-avr@fqdn.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, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/* $Id$ */
#include "ac_cfg.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
#include "avr.h"
#include "pindefs.h"
#include "pgm.h"
#include "par.h"
#include "serbb.h"
#define SLOW_TOGGLE 0
extern char * progname;
extern int do_cycles;
extern int verbose;
static int bitbang_setpin(PROGRAMMER * pgm, int pin, int value)
{
if ( pgm->flag )
serbb_setpin(pgm->fd,pin,value);
else
par_setpin(pgm->fd,pin,value);
return 0;
}
static int bitbang_getpin(PROGRAMMER * pgm, int pin)
{
if ( pgm->flag )
return serbb_getpin(pgm->fd,pin);
else
return par_getpin(pgm->fd,pin);
}
static int bitbang_highpulsepin(PROGRAMMER * pgm, int pin)
{
if ( pgm->flag )
return serbb_highpulsepin(pgm->fd,pin);
else
return par_highpulsepin(pgm->fd,pin);
}
/*
* 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 bitbang_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 */
bitbang_setpin(pgm, pgm->pinno[PIN_AVR_MOSI], b);
bitbang_setpin(pgm, pgm->pinno[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 = bitbang_getpin(pgm, pgm->pinno[PIN_AVR_MISO]);
bitbang_setpin(pgm, pgm->pinno[PIN_AVR_SCK], 0);
rbyte |= r << i;
}
return rbyte;
}
int bitbang_rdy_led(PROGRAMMER * pgm, int value)
{
bitbang_setpin(pgm, pgm->pinno[PIN_LED_RDY], !value);
return 0;
}
int bitbang_err_led(PROGRAMMER * pgm, int value)
{
bitbang_setpin(pgm, pgm->pinno[PIN_LED_ERR], !value);
return 0;
}
int bitbang_pgm_led(PROGRAMMER * pgm, int value)
{
bitbang_setpin(pgm, pgm->pinno[PIN_LED_PGM], !value);
return 0;
}
int bitbang_vfy_led(PROGRAMMER * pgm, int value)
{
bitbang_setpin(pgm, pgm->pinno[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, unsigned char cmd[4],
unsigned char res[4])
{
int i;
for (i=0; i<4; i++) {
res[i] = bitbang_txrx(pgm, cmd[i]);
}
if(verbose >= 2)
{
fprintf(stderr, "bitbang_cmd(): [ ");
for(i = 0; i < 4; i++)
fprintf(stderr, "%02X ", cmd[i]);
fprintf(stderr, "] [ ");
for(i = 0; i < 4; i++)
{
fprintf(stderr, "%02X ", res[i]);
}
fprintf(stderr, "]\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];
if (p->op[AVR_OP_CHIP_ERASE] == NULL) {
fprintf(stderr, "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];
if (p->op[AVR_OP_PGM_ENABLE] == NULL) {
fprintf(stderr, "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;
pgm->powerup(pgm);
usleep(20000);
bitbang_setpin(pgm, pgm->pinno[PIN_AVR_SCK], 0);
bitbang_setpin(pgm, pgm->pinno[PIN_AVR_RESET], 0);
usleep(20000);
bitbang_highpulsepin(pgm, pgm->pinno[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 (strcmp(p->desc, "AT90S1200")==0) {
pgm->program_enable(pgm, p);
}
else {
tries = 0;
do {
rc = pgm->program_enable(pgm, p);
if ((rc == 0)||(rc == -1))
break;
bitbang_highpulsepin(pgm, pgm->pinno[p->retry_pulse/*PIN_AVR_SCK*/]);
tries++;
} while (tries < 65);
/*
* can't sync with the device, maybe it's not attached?
*/
if (rc) {
fprintf(stderr, "%s: AVR device not responding\n", progname);
return -1;
}
}
return 0;
}

43
bitbang.h Normal file
View File

@ -0,0 +1,43 @@
/*
* avrdude - A Downloader/Uploader for AVR device programmers
* Copyright (C) 2000, 2001, 2002, 2003 Brian S. Dean <bsd@bsdhome.com>
* Copyright (C) 2005 Michael Holzt <kju-avr@fqdn.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, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/* $Id$ */
#ifndef bitbang_h
#define bitbang_h
int bitbang_setpin(int fd, int pin, int value);
int bitbang_getpin(int fd, int pin);
int bitbang_highpulsepin(int fd, int pin);
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, unsigned char cmd[4],
unsigned char res[4]);
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);
#endif

View File

@ -29,6 +29,7 @@
#include "config.h" #include "config.h"
#include "lists.h" #include "lists.h"
#include "par.h" #include "par.h"
#include "serbb.h"
#include "pindefs.h" #include "pindefs.h"
#include "ppi.h" #include "ppi.h"
#include "pgm.h" #include "pgm.h"
@ -49,7 +50,7 @@ extern char * progname;
int yylex(void); int yylex(void);
int yyerror(char * errmsg); int yyerror(char * errmsg);
static int assign_pin(int pinno, TOKEN * v); static int assign_pin(int pinno, TOKEN * v, int invert);
static int which_opcode(TOKEN * opcode); static int which_opcode(TOKEN * opcode);
static int parse_cmdbits(OPCODE * op); static int parse_cmdbits(OPCODE * op);
@ -110,6 +111,7 @@ static int parse_cmdbits(OPCODE * op);
%token K_READMEM %token K_READMEM
%token K_RESET %token K_RESET
%token K_RETRY_PULSE %token K_RETRY_PULSE
%token K_SERBB
%token K_SERIAL %token K_SERIAL
%token K_SCK %token K_SCK
%token K_SIZE %token K_SIZE
@ -159,6 +161,7 @@ static int parse_cmdbits(OPCODE * op);
%token TKN_COMMA %token TKN_COMMA
%token TKN_EQUAL %token TKN_EQUAL
%token TKN_SEMI %token TKN_SEMI
%token TKN_TILDE
%token TKN_NUMBER %token TKN_NUMBER
%token TKN_STRING %token TKN_STRING
%token TKN_ID %token TKN_ID
@ -325,6 +328,12 @@ prog_parm :
} }
} | } |
K_TYPE TKN_EQUAL K_SERBB {
{
serbb_initpgm(current_prog);
}
} |
K_TYPE TKN_EQUAL K_STK500 { K_TYPE TKN_EQUAL K_STK500 {
{ {
stk500_initpgm(current_prog); stk500_initpgm(current_prog);
@ -418,15 +427,26 @@ prog_parm :
} | } |
K_RESET TKN_EQUAL TKN_NUMBER { free_token($1); K_RESET TKN_EQUAL TKN_NUMBER { free_token($1);
assign_pin(PIN_AVR_RESET, $3); } | assign_pin(PIN_AVR_RESET, $3, 0); } |
K_SCK TKN_EQUAL TKN_NUMBER { free_token($1); K_SCK TKN_EQUAL TKN_NUMBER { free_token($1);
assign_pin(PIN_AVR_SCK, $3); } | assign_pin(PIN_AVR_SCK, $3, 0); } |
K_MOSI TKN_EQUAL TKN_NUMBER { assign_pin(PIN_AVR_MOSI, $3); } | K_MOSI TKN_EQUAL TKN_NUMBER { assign_pin(PIN_AVR_MOSI, $3, 0); } |
K_MISO TKN_EQUAL TKN_NUMBER { assign_pin(PIN_AVR_MISO, $3); } | K_MISO TKN_EQUAL TKN_NUMBER { assign_pin(PIN_AVR_MISO, $3, 0); } |
K_ERRLED TKN_EQUAL TKN_NUMBER { assign_pin(PIN_LED_ERR, $3); } | K_ERRLED TKN_EQUAL TKN_NUMBER { assign_pin(PIN_LED_ERR, $3, 0); } |
K_RDYLED TKN_EQUAL TKN_NUMBER { assign_pin(PIN_LED_RDY, $3); } | K_RDYLED TKN_EQUAL TKN_NUMBER { assign_pin(PIN_LED_RDY, $3, 0); } |
K_PGMLED TKN_EQUAL TKN_NUMBER { assign_pin(PIN_LED_PGM, $3); } | K_PGMLED TKN_EQUAL TKN_NUMBER { assign_pin(PIN_LED_PGM, $3, 0); } |
K_VFYLED TKN_EQUAL TKN_NUMBER { assign_pin(PIN_LED_VFY, $3); } K_VFYLED TKN_EQUAL TKN_NUMBER { assign_pin(PIN_LED_VFY, $3, 0); } |
K_RESET TKN_EQUAL TKN_TILDE TKN_NUMBER { free_token($1);
assign_pin(PIN_AVR_RESET, $4, 1); } |
K_SCK TKN_EQUAL TKN_TILDE TKN_NUMBER { free_token($1);
assign_pin(PIN_AVR_SCK, $4, 1); } |
K_MOSI TKN_EQUAL TKN_TILDE TKN_NUMBER { assign_pin(PIN_AVR_MOSI, $4, 1); } |
K_MISO TKN_EQUAL TKN_TILDE TKN_NUMBER { assign_pin(PIN_AVR_MISO, $4, 1); } |
K_ERRLED TKN_EQUAL TKN_TILDE TKN_NUMBER { assign_pin(PIN_LED_ERR, $4, 1); } |
K_RDYLED TKN_EQUAL TKN_TILDE TKN_NUMBER { assign_pin(PIN_LED_RDY, $4, 1); } |
K_PGMLED TKN_EQUAL TKN_TILDE TKN_NUMBER { assign_pin(PIN_LED_PGM, $4, 1); } |
K_VFYLED TKN_EQUAL TKN_TILDE TKN_NUMBER { assign_pin(PIN_LED_VFY, $4, 1); }
; ;
@ -854,7 +874,7 @@ static char * vtypestr(int type)
#endif #endif
static int assign_pin(int pinno, TOKEN * v) static int assign_pin(int pinno, TOKEN * v, int invert)
{ {
int value; int value;
@ -867,6 +887,8 @@ static int assign_pin(int pinno, TOKEN * v)
progname, lineno, infile); progname, lineno, infile);
exit(1); exit(1);
} }
if (invert)
value |= PIN_INVERSE;
current_prog->pinno[pinno] = value; current_prog->pinno[pinno] = value;

View File

@ -129,9 +129,10 @@ from the contents of a file, while interactive mode is useful for
exploring memory contents, modifing individual bytes of eeprom, exploring memory contents, modifing individual bytes of eeprom,
programming fuse/lock bits, etc. programming fuse/lock bits, etc.
AVRDUDE supports five basic programmer types: Atmel's STK500, AVRDUDE supports six basic programmer types: Atmel's STK500,
Atmel's JTAG ICE mkII, appnote Atmel's JTAG ICE mkII, appnote
avr910, appnote avr109 (including the AVR Butterfly), avr910, appnote avr109 (including the AVR Butterfly),
serial bit-bang adapters,
and the PPI (parallel port interface). PPI represents a class and the PPI (parallel port interface). PPI represents a class
of simple programmers where the programming lines are directly of simple programmers where the programming lines are directly
connected to the PC parallel port. Several pin configurations exist connected to the PC parallel port. Several pin configurations exist
@ -141,6 +142,14 @@ programmer on the command line or by creating a new entry in its
configuration file. All that's usually required for a new entry is to configuration file. All that's usually required for a new entry is to
tell AVRDUDE which pins to use for each programming function. tell AVRDUDE which pins to use for each programming function.
A number of equally simple bit-bang programming adapters that connect
to a serial port are supported as well, among them the popular
Ponyprog serial adapter, and the DASA and DASA3 adapters that used to
be supported by uisp(1). Note that these adapters are meant to be
attached to a physical serial port. Connecting to a serial port
emulated on top of USB is likely to not work at all, or to work
abysmally slow.
The STK500, JTAG ICE, avr910, and avr109/butterfly use the serial port to communicate with the PC. The STK500, JTAG ICE, avr910, and avr109/butterfly use the serial port to communicate with the PC.
The STK500, JTAG ICE, and avr910 contain on-board logic to control the programming of the target The STK500, JTAG ICE, and avr910 contain on-board logic to control the programming of the target
device. device.

View File

@ -160,6 +160,7 @@ rdyled { yylval=NULL; return K_RDYLED; }
readback_p1 { yylval=NULL; return K_READBACK_P1; } readback_p1 { yylval=NULL; return K_READBACK_P1; }
readback_p2 { yylval=NULL; return K_READBACK_P2; } readback_p2 { yylval=NULL; return K_READBACK_P2; }
retry_pulse { yylval=NULL; return K_RETRY_PULSE; } retry_pulse { yylval=NULL; return K_RETRY_PULSE; }
serbb { yylval=NULL; return K_SERBB; }
serial { yylval=NULL; return K_SERIAL; } serial { yylval=NULL; return K_SERIAL; }
size { yylval=NULL; return K_SIZE; } size { yylval=NULL; return K_SIZE; }
spmcr { yylval=NULL; return K_SPMCR; } spmcr { yylval=NULL; return K_SPMCR; }
@ -212,6 +213,7 @@ yes { yylval=new_token(K_YES); return K_YES; }
"," { yylval = NULL; pyytext(); return TKN_COMMA; } "," { yylval = NULL; pyytext(); return TKN_COMMA; }
"=" { yylval = NULL; pyytext(); return TKN_EQUAL; } "=" { yylval = NULL; pyytext(); return TKN_EQUAL; }
";" { yylval = NULL; pyytext(); return TKN_SEMI; } ";" { yylval = NULL; pyytext(); return TKN_SEMI; }
"~" { yylval = NULL; pyytext(); return TKN_TILDE; }
"\n" { lineno++; } "\n" { lineno++; }
[ \r\t]+ /* ignore whitespace */ [ \r\t]+ /* ignore whitespace */

328
par.c
View File

@ -37,8 +37,8 @@
#include "avr.h" #include "avr.h"
#include "pindefs.h" #include "pindefs.h"
#include "pgm.h" #include "pgm.h"
#include "par.h"
#include "ppi.h" #include "ppi.h"
#include "bitbang.h"
#define SLOW_TOGGLE 0 #define SLOW_TOGGLE 0
@ -49,7 +49,7 @@ struct ppipins_t {
int inverted; int inverted;
}; };
static struct ppipins_t pins[] = { struct ppipins_t ppipins[] = {
{ 1, PPICTRL, 0x01, 1 }, { 1, PPICTRL, 0x01, 1 },
{ 2, PPIDATA, 0x01, 0 }, { 2, PPIDATA, 0x01, 0 },
{ 3, PPIDATA, 0x02, 0 }, { 3, PPIDATA, 0x02, 0 },
@ -69,66 +69,30 @@ static struct ppipins_t pins[] = {
{ 17, PPICTRL, 0x08, 1 } { 17, PPICTRL, 0x08, 1 }
}; };
#define NPINS (sizeof(pins)/sizeof(struct ppipins_t)) #define NPINS (sizeof(ppipins)/sizeof(struct ppipins_t))
extern char * progname; extern char * progname;
extern int do_cycles; extern int do_cycles;
extern int verbose; extern int verbose;
int par_setpin(int fd, int pin, int value)
static int par_setpin (int fd, int pin, int value);
static int par_getpin (int fd, int pin);
static int par_pulsepin (int fd, int pin);
static int par_rdy_led (PROGRAMMER * pgm, int value);
static int par_err_led (PROGRAMMER * pgm, int value);
static int par_pgm_led (PROGRAMMER * pgm, int value);
static int par_vfy_led (PROGRAMMER * pgm, int value);
static int par_cmd (PROGRAMMER * pgm, unsigned char cmd[4],
unsigned char res[4]);
static int par_chip_erase (PROGRAMMER * pgm, AVRPART * p);
static int par_program_enable (PROGRAMMER * pgm, AVRPART * p);
static void par_powerup (PROGRAMMER * pgm);
static void par_powerdown (PROGRAMMER * pgm);
static int par_initialize (PROGRAMMER * pgm, AVRPART * p);
static void par_disable (PROGRAMMER * pgm);
static void par_enable (PROGRAMMER * pgm);
static int par_open (PROGRAMMER * pgm, char * port);
static void par_close (PROGRAMMER * pgm);
static int par_setpin(int fd, int pin, int value)
{ {
pin &= PIN_MASK;
if (pin < 1 || pin > 17) if (pin < 1 || pin > 17)
return -1; return -1;
pin--; pin--;
if (pins[pin].inverted) if (ppipins[pin].inverted)
value = !value; value = !value;
if (value) if (value)
ppi_set(fd, pins[pin].reg, pins[pin].bit); ppi_set(fd, ppipins[pin].reg, ppipins[pin].bit);
else else
ppi_clr(fd, pins[pin].reg, pins[pin].bit); ppi_clr(fd, ppipins[pin].reg, ppipins[pin].bit);
#if SLOW_TOGGLE #if SLOW_TOGGLE
usleep(1000); usleep(1000);
@ -138,28 +102,30 @@ static int par_setpin(int fd, int pin, int value)
} }
static int par_getpin(int fd, int pin) int par_getpin(int fd, int pin)
{ {
int value; int value;
pin &= PIN_MASK;
if (pin < 1 || pin > 17) if (pin < 1 || pin > 17)
return -1; return -1;
pin--; pin--;
value = ppi_get(fd, pins[pin].reg, pins[pin].bit); value = ppi_get(fd, ppipins[pin].reg, ppipins[pin].bit);
if (value) if (value)
value = 1; value = 1;
if (pins[pin].inverted) if (ppipins[pin].inverted)
value = !value; value = !value;
return value; return value;
} }
static int par_pulsepin(int fd, int pin) int par_highpulsepin(int fd, int pin)
{ {
if (pin < 1 || pin > 17) if (pin < 1 || pin > 17)
@ -167,13 +133,11 @@ static int par_pulsepin(int fd, int pin)
pin--; pin--;
ppi_toggle(fd, pins[pin].reg, pins[pin].bit); ppi_set(fd, ppipins[pin].reg, ppipins[pin].bit);
#if SLOW_TOGGLE #if SLOW_TOGGLE
usleep(1000); usleep(1000);
#endif #endif
ppi_clr(fd, ppipins[pin].reg, ppipins[pin].bit);
ppi_toggle(fd, pins[pin].reg, pins[pin].bit);
#if SLOW_TOGGLE #if SLOW_TOGGLE
usleep(1000); usleep(1000);
@ -184,15 +148,17 @@ static int par_pulsepin(int fd, int pin)
int par_getpinmask(int pin) int par_getpinmask(int pin)
{ {
pin &= PIN_MASK;
if (pin < 1 || pin > 17) if (pin < 1 || pin > 17)
return -1; return -1;
return pins[pin-1].bit; return ppipins[pin-1].bit;
} }
static char vccpins_buf[64]; char vccpins_buf[64];
static char * vccpins_str(unsigned int pmask) char * vccpins_str(unsigned int pmask)
{ {
unsigned int mask; unsigned int mask;
int pin; int pin;
@ -214,169 +180,10 @@ static char * vccpins_str(unsigned int pmask)
return b; return b;
} }
/*
* transmit and receive a byte of data to/from the AVR device
*/
static unsigned char par_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 par_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 */
par_setpin(pgm->fd, pgm->pinno[PIN_AVR_MOSI], b);
par_setpin(pgm->fd, pgm->pinno[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 = par_getpin(pgm->fd, pgm->pinno[PIN_AVR_MISO]);
par_setpin(pgm->fd, pgm->pinno[PIN_AVR_SCK], 0);
rbyte |= r << i;
}
return rbyte;
}
static int par_rdy_led(PROGRAMMER * pgm, int value)
{
par_setpin(pgm->fd, pgm->pinno[PIN_LED_RDY], !value);
return 0;
}
static int par_err_led(PROGRAMMER * pgm, int value)
{
par_setpin(pgm->fd, pgm->pinno[PIN_LED_ERR], !value);
return 0;
}
static int par_pgm_led(PROGRAMMER * pgm, int value)
{
par_setpin(pgm->fd, pgm->pinno[PIN_LED_PGM], !value);
return 0;
}
static int par_vfy_led(PROGRAMMER * pgm, int value)
{
par_setpin(pgm->fd, pgm->pinno[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
*/
static int par_cmd(PROGRAMMER * pgm, unsigned char cmd[4],
unsigned char res[4])
{
int i;
for (i=0; i<4; i++) {
res[i] = par_txrx(pgm, cmd[i]);
}
if(verbose >= 2)
{
fprintf(stderr, "par_cmd(): [ ");
for(i = 0; i < 4; i++)
fprintf(stderr, "%02X ", cmd[i]);
fprintf(stderr, "] [ ");
for(i = 0; i < 4; i++)
{
fprintf(stderr, "%02X ", res[i]);
}
fprintf(stderr, "]\n");
}
return 0;
}
/*
* issue the 'chip erase' command to the AVR device
*/
static int par_chip_erase(PROGRAMMER * pgm, AVRPART * p)
{
unsigned char cmd[4];
unsigned char res[4];
if (p->op[AVR_OP_CHIP_ERASE] == NULL) {
fprintf(stderr, "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
*/
static int par_program_enable(PROGRAMMER * pgm, AVRPART * p)
{
unsigned char cmd[4];
unsigned char res[4];
if (p->op[AVR_OP_PGM_ENABLE] == NULL) {
fprintf(stderr, "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;
}
/* /*
* apply power to the AVR processor * apply power to the AVR processor
*/ */
static void par_powerup(PROGRAMMER * pgm) void par_powerup(PROGRAMMER * pgm)
{ {
ppi_set(pgm->fd, PPIDATA, pgm->pinno[PPI_AVR_VCC]); /* power up */ ppi_set(pgm->fd, PPIDATA, pgm->pinno[PPI_AVR_VCC]); /* power up */
usleep(100000); usleep(100000);
@ -386,71 +193,17 @@ static void par_powerup(PROGRAMMER * pgm)
/* /*
* remove power from the AVR processor * remove power from the AVR processor
*/ */
static void par_powerdown(PROGRAMMER * pgm) void par_powerdown(PROGRAMMER * pgm)
{ {
ppi_clr(pgm->fd, PPIDATA, pgm->pinno[PPI_AVR_VCC]); /* power down */ ppi_clr(pgm->fd, PPIDATA, pgm->pinno[PPI_AVR_VCC]); /* power down */
} }
void par_disable(PROGRAMMER * pgm)
/*
* initialize the AVR device and prepare it to accept commands
*/
static int par_initialize(PROGRAMMER * pgm, AVRPART * p)
{
int rc;
int tries;
pgm->powerup(pgm);
usleep(20000);
par_setpin(pgm->fd, pgm->pinno[PIN_AVR_SCK], 0);
par_setpin(pgm->fd, pgm->pinno[PIN_AVR_RESET], 0);
usleep(20000);
par_pulsepin(pgm->fd, pgm->pinno[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 (strcmp(p->desc, "AT90S1200")==0) {
pgm->program_enable(pgm, p);
}
else {
tries = 0;
do {
rc = pgm->program_enable(pgm, p);
if ((rc == 0)||(rc == -1))
break;
par_pulsepin(pgm->fd, pgm->pinno[p->retry_pulse/*PIN_AVR_SCK*/]);
tries++;
} while (tries < 65);
/*
* can't sync with the device, maybe it's not attached?
*/
if (rc) {
fprintf(stderr, "%s: AVR device not responding\n", progname);
return -1;
}
}
return 0;
}
static void par_disable(PROGRAMMER * pgm)
{ {
ppi_set(pgm->fd, PPIDATA, pgm->pinno[PPI_AVR_BUFF]); ppi_set(pgm->fd, PPIDATA, pgm->pinno[PPI_AVR_BUFF]);
} }
static void par_enable(PROGRAMMER * pgm) void par_enable(PROGRAMMER * pgm)
{ {
/* /*
* Prepare to start talking to the connected device - pull reset low * Prepare to start talking to the connected device - pull reset low
@ -472,8 +225,7 @@ static void par_enable(PROGRAMMER * pgm)
ppi_clr(pgm->fd, PPIDATA, pgm->pinno[PPI_AVR_BUFF]); ppi_clr(pgm->fd, PPIDATA, pgm->pinno[PPI_AVR_BUFF]);
} }
int par_open(PROGRAMMER * pgm, char * port)
static int par_open(PROGRAMMER * pgm, char * port)
{ {
int rc; int rc;
@ -507,7 +259,7 @@ static int par_open(PROGRAMMER * pgm, char * port)
} }
static void par_close(PROGRAMMER * pgm) void par_close(PROGRAMMER * pgm)
{ {
/* /*
* Restore pin values before closing, * Restore pin values before closing,
@ -523,8 +275,7 @@ static void par_close(PROGRAMMER * pgm)
pgm->fd = -1; pgm->fd = -1;
} }
void par_display(PROGRAMMER * pgm, char * p)
static void par_display(PROGRAMMER * pgm, char * p)
{ {
char vccpins[64]; char vccpins[64];
char buffpins[64]; char buffpins[64];
@ -574,21 +325,22 @@ void par_initpgm(PROGRAMMER * pgm)
{ {
strcpy(pgm->type, "PPI"); strcpy(pgm->type, "PPI");
pgm->rdy_led = par_rdy_led; pgm->rdy_led = bitbang_rdy_led;
pgm->err_led = par_err_led; pgm->err_led = bitbang_err_led;
pgm->pgm_led = par_pgm_led; pgm->pgm_led = bitbang_pgm_led;
pgm->vfy_led = par_vfy_led; pgm->vfy_led = bitbang_vfy_led;
pgm->initialize = par_initialize; pgm->initialize = bitbang_initialize;
pgm->display = par_display; pgm->display = par_display;
pgm->enable = par_enable; pgm->enable = par_enable;
pgm->disable = par_disable; pgm->disable = par_disable;
pgm->powerup = par_powerup; pgm->powerup = par_powerup;
pgm->powerdown = par_powerdown; pgm->powerdown = par_powerdown;
pgm->program_enable = par_program_enable; pgm->program_enable = bitbang_program_enable;
pgm->chip_erase = par_chip_erase; pgm->chip_erase = bitbang_chip_erase;
pgm->cmd = par_cmd; pgm->cmd = bitbang_cmd;
pgm->open = par_open; pgm->open = par_open;
pgm->close = par_close; pgm->close = par_close;
/* this is a parallel port bitbang device */
pgm->flag = 0;
} }

3
par.h
View File

@ -25,6 +25,9 @@
void par_initpgm (PROGRAMMER * pgm); void par_initpgm (PROGRAMMER * pgm);
int par_getpinmask(int pin); int par_getpinmask(int pin);
int par_setpin(int fd, int pin, int value);
int par_getpin(int fd, int pin);
int par_highpulsepin(int fd, int pin);
#endif #endif

1
pgm.h
View File

@ -83,6 +83,7 @@ typedef struct programmer_t {
int (*set_sck_period) (struct programmer_t * pgm, double v); int (*set_sck_period) (struct programmer_t * pgm, double v);
char config_file[PATH_MAX]; /* config file where defined */ char config_file[PATH_MAX]; /* config file where defined */
int lineno; /* config file line number */ int lineno; /* config file line number */
char flag; /* for private use of the programmer */
} PROGRAMMER; } PROGRAMMER;

View File

@ -35,6 +35,8 @@ enum {
PIN_LED_VFY, PIN_LED_VFY,
N_PINS N_PINS
}; };
#define PIN_INVERSE 0x80 /* flag for inverted pin in serbb */
#define PIN_MASK 0x7f
#define LED_ON(fd,pin) ppi_setpin(fd,pin,0) #define LED_ON(fd,pin) ppi_setpin(fd,pin,0)
#define LED_OFF(fd,pin) ppi_setpin(fd,pin,1) #define LED_OFF(fd,pin) ppi_setpin(fd,pin,1)

33
serbb.h Normal file
View File

@ -0,0 +1,33 @@
/*
* avrdude - A Downloader/Uploader for AVR device programmers
* Copyright (C) 2000, 2001, 2002, 2003 Brian S. Dean <bsd@bsdhome.com>
* Copyright (C) 2005 Michael Holzt <kju-avr@fqdn.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, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/* $Id$ */
#ifndef serbb_h
#define serbb_h
void serbb_initpgm (PROGRAMMER * pgm);
int serbb_setpin(int fd, int pin, int value);
int serbb_getpin(int fd, int pin);
int serbb_highpulsepin(int fd, int pin);
#endif

271
serbb_posix.c Normal file
View File

@ -0,0 +1,271 @@
/*
* avrdude - A Downloader/Uploader for AVR device programmers
* Copyright (C) 2000, 2001, 2002, 2003 Brian S. Dean <bsd@bsdhome.com>
* Copyright (C) 2005 Michael Holzt <kju-avr@fqdn.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, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/* $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 "avr.h"
#include "pindefs.h"
#include "pgm.h"
#include "bitbang.h"
#undef DEBUG
extern char *progname;
struct termios oldmode;
/*
serial port/pin mapping
1 cd <-
2 rxd <-
3 txd ->
4 dtr ->
5 dsr <-
6 rts ->
7 cts <-
*/
int serregbits[] =
{ TIOCM_CD, 0, 0, TIOCM_DTR, TIOCM_DSR, TIOCM_RTS, TIOCM_CTS };
#ifdef DEBUG
char *serpins[7] =
{ "CD", "RXD", "TXD ~RESET", "DTR MOSI", "DSR", "RTS SCK", "CTS MISO" };
#endif
void serbb_setpin(int fd, int pin, int value)
{
unsigned int ctl;
if (pin & PIN_INVERSE)
{
value = !value;
pin &= PIN_MASK;
}
if ( pin < 1 || pin > 7 )
return;
pin--;
#ifdef DEBUG
printf("%s to %d\n",serpins[pin],value);
#endif
switch ( pin )
{
case 2: /* txd */
ioctl(fd, value ? TIOCSBRK : TIOCCBRK, 0);
return;
case 3: /* dtr, rts */
case 5: ioctl(fd, TIOCMGET, &ctl);
if ( value )
ctl |= serregbits[pin];
else
ctl &= ~(serregbits[pin]);
ioctl(fd, TIOCMSET, &ctl);
return;
default: /* impossible */
return;
}
}
int serbb_getpin(int fd, int pin)
{
unsigned int ctl;
unsigned char invert;
if (pin & PIN_INVERSE)
{
invert = 1;
pin &= PIN_MASK;
} else
invert = 0;
if ( pin < 1 || pin > 7 )
return(-1);
pin --;
switch ( pin )
{
case 1: /* rxd, currently not implemented, FIXME */
return(-1);
case 0: /* cd, dsr, dtr, rts, cts */
case 3:
case 4:
case 5:
case 6: ioctl(fd, TIOCMGET, &ctl);
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);
}
}
int serbb_highpulsepin(int fd, int pin)
{
if (pin < 1 || pin > 7)
return -1;
serbb_setpin(fd, pin, 1);
#if SLOW_TOGGLE
usleep(1000);
#endif
serbb_setpin(fd, pin, 0);
#if SLOW_TOGGLE
usleep(1000);
#endif
return 0;
}
void serbb_display(PROGRAMMER *pgm, char *p)
{
/* MAYBE */
}
void serbb_enable(PROGRAMMER *pgm)
{
/* nothing */
}
void serbb_disable(PROGRAMMER *pgm)
{
/* nothing */
}
void serbb_powerup(PROGRAMMER *pgm)
{
/* nothing */
}
void serbb_powerdown(PROGRAMMER *pgm)
{
/* nothing */
}
int serbb_open(PROGRAMMER *pgm, char *port)
{
struct termios mode;
int flags;
/* adapted from uisp code */
pgm->fd = open(port, O_RDWR | O_NOCTTY | O_NONBLOCK);
if ( pgm->fd > 0 )
{
tcgetattr(pgm->fd, &mode);
oldmode = mode;
cfmakeraw(&mode);
mode.c_iflag &= ~(INPCK | IXOFF | IXON);
mode.c_cflag &= ~(HUPCL | CSTOPB | CRTSCTS);
mode.c_cflag |= (CLOCAL | CREAD);
mode.c_cc [VMIN] = 1;
mode.c_cc [VTIME] = 0;
tcsetattr(pgm->fd, TCSANOW, &mode);
/* Clear O_NONBLOCK flag. */
flags = fcntl(pgm->fd, F_GETFL, 0);
if (flags == -1)
{
fprintf(stderr, "%s: Can not get flags\n", progname);
return(-1);
}
flags &= ~O_NONBLOCK;
if (fcntl(pgm->fd, F_SETFL, flags) == -1)
{
fprintf(stderr, "%s: Can not clear nonblock flag\n", progname);
return(-1);
}
}
return(0);
}
void serbb_close(PROGRAMMER *pgm)
{
tcsetattr(pgm->fd, TCSADRAIN, &oldmode);
return;
}
void serbb_initpgm(PROGRAMMER *pgm)
{
strcpy(pgm->type, "SERBB");
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->open = serbb_open;
pgm->close = serbb_close;
/* this is a serial port bitbang device */
pgm->flag = 1;
}
#endif /* WIN32NATIVE */

372
serbb_win32.c Normal file
View File

@ -0,0 +1,372 @@
/*
* avrdude - A Downloader/Uploader for AVR device programmers
* Copyright (C) 2003, 2004 Martin J. Thomas <mthomas@rhrk.uni-kl.de>
* Copyright (C) 2005 Michael Holzt <kju-avr@fqdn.org>
* 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, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/* $Id$ */
/*
* Win32 serial bitbanging interface for avrdude.
*/
#if defined(WIN32NATIVE)
#include "ac_cfg.h"
#include <windows.h>
#include <stdio.h>
#include "avr.h"
#include "pindefs.h"
#include "pgm.h"
#include "bitbang.h"
extern char *progname;
extern int verbose;
/* cached status lines */
static int dtr, rts, txd;
#define W32SERBUFSIZE 1024
/*
serial port/pin mapping
1 cd <-
2 rxd <-
3 txd ->
4 dtr ->
5 dsr <-
6 rts ->
7 cts <-
Negative pin # means negated value.
*/
void serbb_setpin(int fd, int pin, int value)
{
HANDLE hComPort = (HANDLE)fd;
LPVOID lpMsgBuf;
DWORD dwFunc;
const char *name;
if (pin & PIN_INVERSE)
{
value = !value;
pin &= PIN_MASK;
}
if (pin < 1 || pin > 7)
return;
pin--;
switch (pin)
{
case 2: /* txd */
dwFunc = value? SETBREAK: CLRBREAK;
name = value? "SETBREAK": "CLRBREAK";
txd = value;
break;
case 3: /* dtr */
dwFunc = value? SETDTR: CLRDTR;
name = value? "SETDTR": "CLRDTR";
dtr = value;
break;
case 5: /* rts */
dwFunc = value? SETRTS: CLRRTS;
name = value? "SETRTS": "CLRRTS";
break;
default:
if (verbose)
fprintf(stderr,
"%s: serbb_setpin(): unknown pin %d\n",
progname, pin + 1);
return;
}
if (verbose > 4)
fprintf(stderr,
"%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);
fprintf(stderr,
"%s: serbb_setpin(): SetCommState() failed: %s\n",
progname, (char *)lpMsgBuf);
CloseHandle(hComPort);
LocalFree(lpMsgBuf);
exit(1);
}
return;
}
int serbb_getpin(int fd, int pin)
{
HANDLE hComPort = (HANDLE)fd;
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 > 7)
return -1;
pin --;
if (pin == 0 /* cd */ || pin == 4 /* dsr */ || pin == 6 /* 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);
fprintf(stderr,
"%s: serbb_setpin(): GetCommModemStatus() failed: %s\n",
progname, (char *)lpMsgBuf);
CloseHandle(hComPort);
LocalFree(lpMsgBuf);
exit(1);
}
if (verbose > 4)
fprintf(stderr,
"%s: serbb_getpin(): GetCommState() => 0x%lx\n",
progname, modemstate);
switch (pin)
{
case 0:
modemstate &= MS_RLSD_ON;
break;
case 4:
modemstate &= MS_DSR_ON;
break;
case 6:
modemstate &= MS_CTS_ON;
break;
}
rv = modemstate != 0;
if (invert)
rv = !rv;
return rv;
}
switch (pin)
{
case 2: /* txd */
rv = txd;
name = "TXD";
break;
case 3: /* dtr */
rv = dtr;
name = "DTR";
break;
case 5: /* rts */
rv = rts;
name = "RTS";
break;
default:
if (verbose)
fprintf(stderr,
"%s: serbb_getpin(): unknown pin %d\n",
progname, pin + 1);
return -1;
}
if (verbose > 4)
fprintf(stderr,
"%s: serbb_getpin(): return cached state for %s\n",
progname, name);
if (invert)
rv = !rv;
return rv;
}
int serbb_highpulsepin(int fd, int pin)
{
if (pin < 1 || pin > 7)
return -1;
serbb_setpin(fd, pin, 1);
#if SLOW_TOGGLE
usleep(1000);
#endif
serbb_setpin(fd, pin, 0);
#if SLOW_TOGGLE
usleep(1000);
#endif
return 0;
}
void serbb_display(PROGRAMMER *pgm, char *p)
{
/* MAYBE */
}
void serbb_enable(PROGRAMMER *pgm)
{
/* nothing */
}
void serbb_disable(PROGRAMMER *pgm)
{
/* nothing */
}
void serbb_powerup(PROGRAMMER *pgm)
{
/* nothing */
}
void serbb_powerdown(PROGRAMMER *pgm)
{
/* nothing */
}
int serbb_open(PROGRAMMER *pgm, char *port)
{
DCB dcb;
LPVOID lpMsgBuf;
HANDLE hComPort = INVALID_HANDLE_VALUE;
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);
fprintf(stderr, "%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);
fprintf(stderr, "%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);
fprintf(stderr, "%s: ser_open(): can't set com-state for \"%s\"\n",
progname, port);
return -1;
}
if (verbose > 2)
fprintf(stderr,
"%s: ser_open(): opened comm port \"%s\", handle 0x%x\n",
progname, port, (int)hComPort);
pgm->fd = (int)hComPort;
dtr = rts = txd = 0;
return 0;
}
void serbb_close(PROGRAMMER *pgm)
{
HANDLE hComPort=(HANDLE)pgm->fd;
if (hComPort != INVALID_HANDLE_VALUE)
CloseHandle (hComPort);
if (verbose > 2)
fprintf(stderr,
"%s: ser_close(): closed comm port handle 0x%x\n",
progname, (int)hComPort);
hComPort = INVALID_HANDLE_VALUE;
}
void serbb_initpgm(PROGRAMMER *pgm)
{
strcpy(pgm->type, "SERBB");
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->open = serbb_open;
pgm->close = serbb_close;
/* this is a serial port bitbang device */
pgm->flag = 1;
}
#endif /* WIN32NATIVE */