From 5c8f87e395dd98d8fd5821c1123098b490b68785 Mon Sep 17 00:00:00 2001 From: Joerg Wunsch Date: Sun, 18 Sep 2005 20:12:23 +0000 Subject: [PATCH] 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 --- ChangeLog | 20 +++ Makefile.am | 5 + NEWS | 3 + avrdude.1 | 14 +- bitbang.c | 280 +++++++++++++++++++++++++++++++++++ bitbang.h | 43 ++++++ config_gram.y | 42 ++++-- doc/avrdude.texi | 13 +- lexer.l | 2 + par.c | 328 +++++------------------------------------ par.h | 3 + pgm.h | 1 + pindefs.h | 2 + serbb.h | 33 +++++ serbb_posix.c | 271 ++++++++++++++++++++++++++++++++++ serbb_win32.c | 372 +++++++++++++++++++++++++++++++++++++++++++++++ 16 files changed, 1130 insertions(+), 302 deletions(-) create mode 100644 bitbang.c create mode 100644 bitbang.h create mode 100644 serbb.h create mode 100644 serbb_posix.c create mode 100644 serbb_win32.c diff --git a/ChangeLog b/ChangeLog index 83dc43b8..6b3747fc 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,23 @@ +2005-09-18 Joerg Wunsch + + 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 * avrdude.conf.in: Patch #4078: add VCC pin definition for DAPA diff --git a/Makefile.am b/Makefile.am index 9ca2895e..24741979 100644 --- a/Makefile.am +++ b/Makefile.am @@ -57,6 +57,8 @@ avrdude_SOURCES = \ avr910.h \ avrpart.c \ avrpart.h \ + bitbang.c \ + bitbang.h \ butterfly.c \ butterfly.h \ config.c \ @@ -85,6 +87,9 @@ avrdude_SOURCES = \ safemode.c \ safemode.h \ serial.h \ + serbb.h \ + serbb_posix.c \ + serbb_win32.c \ ser_posix.c \ ser_win32.c \ stk500.c \ diff --git a/NEWS b/NEWS index 2e15502f..1fa783bf 100644 --- a/NEWS +++ b/NEWS @@ -21,6 +21,9 @@ Current: - ATmega329x/649x - ATtiny25/45/85 + * Support for serial bit-bang adapters: Ponyprog serial, UISP DASA, + UISP DASA3. + * DAPA programmer pinout supported * New "safemode" feature where fuse bits are verified before exit diff --git a/avrdude.1 b/avrdude.1 index 004540b1..81051e95 100644 --- a/avrdude.1 +++ b/avrdude.1 @@ -19,7 +19,7 @@ .\" .\" $Id$ .\" -.Dd DATE August 28, 2005 +.Dd DATE September 18, 2005 .Os .Dt AVRDUDE 1 .Sh NAME @@ -61,7 +61,8 @@ programmer connected directly to a .Xr ppi 4 or .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. .Pp 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 from the MCU when in-system programming is used. .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 port. Both, firmware versions 1.x and 2.x can be handled, but require a diff --git a/bitbang.c b/bitbang.c new file mode 100644 index 00000000..dee3cbc7 --- /dev/null +++ b/bitbang.c @@ -0,0 +1,280 @@ +/* + * avrdude - A Downloader/Uploader for AVR device programmers + * Copyright (C) 2000, 2001, 2002, 2003 Brian S. Dean + * Copyright (C) 2005 Michael Holzt + * + * 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 +#include +#include +#include +#include +#include + +#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; +} + + diff --git a/bitbang.h b/bitbang.h new file mode 100644 index 00000000..b428e604 --- /dev/null +++ b/bitbang.h @@ -0,0 +1,43 @@ +/* + * avrdude - A Downloader/Uploader for AVR device programmers + * Copyright (C) 2000, 2001, 2002, 2003 Brian S. Dean + * Copyright (C) 2005 Michael Holzt + * + * 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 diff --git a/config_gram.y b/config_gram.y index 88c65148..21c842c9 100644 --- a/config_gram.y +++ b/config_gram.y @@ -29,6 +29,7 @@ #include "config.h" #include "lists.h" #include "par.h" +#include "serbb.h" #include "pindefs.h" #include "ppi.h" #include "pgm.h" @@ -49,7 +50,7 @@ extern char * progname; int yylex(void); 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 parse_cmdbits(OPCODE * op); @@ -110,6 +111,7 @@ static int parse_cmdbits(OPCODE * op); %token K_READMEM %token K_RESET %token K_RETRY_PULSE +%token K_SERBB %token K_SERIAL %token K_SCK %token K_SIZE @@ -159,6 +161,7 @@ static int parse_cmdbits(OPCODE * op); %token TKN_COMMA %token TKN_EQUAL %token TKN_SEMI +%token TKN_TILDE %token TKN_NUMBER %token TKN_STRING %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 { { stk500_initpgm(current_prog); @@ -418,15 +427,26 @@ prog_parm : } | 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); - assign_pin(PIN_AVR_SCK, $3); } | - K_MOSI TKN_EQUAL TKN_NUMBER { assign_pin(PIN_AVR_MOSI, $3); } | - K_MISO TKN_EQUAL TKN_NUMBER { assign_pin(PIN_AVR_MISO, $3); } | - K_ERRLED TKN_EQUAL TKN_NUMBER { assign_pin(PIN_LED_ERR, $3); } | - K_RDYLED TKN_EQUAL TKN_NUMBER { assign_pin(PIN_LED_RDY, $3); } | - K_PGMLED TKN_EQUAL TKN_NUMBER { assign_pin(PIN_LED_PGM, $3); } | - K_VFYLED TKN_EQUAL TKN_NUMBER { assign_pin(PIN_LED_VFY, $3); } + assign_pin(PIN_AVR_SCK, $3, 0); } | + 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, 0); } | + 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, 0); } | + 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, 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 -static int assign_pin(int pinno, TOKEN * v) +static int assign_pin(int pinno, TOKEN * v, int invert) { int value; @@ -867,6 +887,8 @@ static int assign_pin(int pinno, TOKEN * v) progname, lineno, infile); exit(1); } + if (invert) + value |= PIN_INVERSE; current_prog->pinno[pinno] = value; diff --git a/doc/avrdude.texi b/doc/avrdude.texi index 2f91262d..69cbd4b7 100644 --- a/doc/avrdude.texi +++ b/doc/avrdude.texi @@ -129,9 +129,10 @@ from the contents of a file, while interactive mode is useful for exploring memory contents, modifing individual bytes of eeprom, 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 avr910, appnote avr109 (including the AVR Butterfly), +serial bit-bang adapters, and the PPI (parallel port interface). PPI represents a class of simple programmers where the programming lines are directly connected to the PC parallel port. Several pin configurations exist @@ -139,7 +140,15 @@ for several variations of the PPI programmers, and AVRDUDE can be be configured to work with them by either specifying the appropriate 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 -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, and avr910 contain on-board logic to control the programming of the target diff --git a/lexer.l b/lexer.l index a8386fc1..c834624e 100644 --- a/lexer.l +++ b/lexer.l @@ -160,6 +160,7 @@ rdyled { yylval=NULL; return K_RDYLED; } readback_p1 { yylval=NULL; return K_READBACK_P1; } readback_p2 { yylval=NULL; return K_READBACK_P2; } retry_pulse { yylval=NULL; return K_RETRY_PULSE; } +serbb { yylval=NULL; return K_SERBB; } serial { yylval=NULL; return K_SERIAL; } size { yylval=NULL; return K_SIZE; } 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_EQUAL; } ";" { yylval = NULL; pyytext(); return TKN_SEMI; } +"~" { yylval = NULL; pyytext(); return TKN_TILDE; } "\n" { lineno++; } [ \r\t]+ /* ignore whitespace */ diff --git a/par.c b/par.c index 33c07be1..fd257b38 100644 --- a/par.c +++ b/par.c @@ -37,8 +37,8 @@ #include "avr.h" #include "pindefs.h" #include "pgm.h" -#include "par.h" #include "ppi.h" +#include "bitbang.h" #define SLOW_TOGGLE 0 @@ -49,7 +49,7 @@ struct ppipins_t { int inverted; }; -static struct ppipins_t pins[] = { +struct ppipins_t ppipins[] = { { 1, PPICTRL, 0x01, 1 }, { 2, PPIDATA, 0x01, 0 }, { 3, PPIDATA, 0x02, 0 }, @@ -69,66 +69,30 @@ static struct ppipins_t pins[] = { { 17, PPICTRL, 0x08, 1 } }; -#define NPINS (sizeof(pins)/sizeof(struct ppipins_t)) +#define NPINS (sizeof(ppipins)/sizeof(struct ppipins_t)) extern char * progname; extern int do_cycles; extern int verbose; - -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) +int par_setpin(int fd, int pin, int value) { + pin &= PIN_MASK; + if (pin < 1 || pin > 17) return -1; pin--; - if (pins[pin].inverted) + if (ppipins[pin].inverted) value = !value; if (value) - ppi_set(fd, pins[pin].reg, pins[pin].bit); + ppi_set(fd, ppipins[pin].reg, ppipins[pin].bit); else - ppi_clr(fd, pins[pin].reg, pins[pin].bit); + ppi_clr(fd, ppipins[pin].reg, ppipins[pin].bit); #if SLOW_TOGGLE 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; + pin &= PIN_MASK; + if (pin < 1 || pin > 17) return -1; pin--; - value = ppi_get(fd, pins[pin].reg, pins[pin].bit); + value = ppi_get(fd, ppipins[pin].reg, ppipins[pin].bit); if (value) value = 1; - if (pins[pin].inverted) + if (ppipins[pin].inverted) value = !value; return value; } -static int par_pulsepin(int fd, int pin) +int par_highpulsepin(int fd, int pin) { if (pin < 1 || pin > 17) @@ -167,13 +133,11 @@ static int par_pulsepin(int fd, int pin) pin--; - ppi_toggle(fd, pins[pin].reg, pins[pin].bit); - + ppi_set(fd, ppipins[pin].reg, ppipins[pin].bit); #if SLOW_TOGGLE usleep(1000); #endif - - ppi_toggle(fd, pins[pin].reg, pins[pin].bit); + ppi_clr(fd, ppipins[pin].reg, ppipins[pin].bit); #if SLOW_TOGGLE usleep(1000); @@ -184,15 +148,17 @@ static int par_pulsepin(int fd, int pin) int par_getpinmask(int pin) { + pin &= PIN_MASK; + if (pin < 1 || pin > 17) return -1; - return pins[pin-1].bit; + return ppipins[pin-1].bit; } -static char vccpins_buf[64]; -static char * vccpins_str(unsigned int pmask) +char vccpins_buf[64]; +char * vccpins_str(unsigned int pmask) { unsigned int mask; int pin; @@ -214,169 +180,10 @@ static char * vccpins_str(unsigned int pmask) 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 */ -static void par_powerup(PROGRAMMER * pgm) +void par_powerup(PROGRAMMER * pgm) { ppi_set(pgm->fd, PPIDATA, pgm->pinno[PPI_AVR_VCC]); /* power up */ usleep(100000); @@ -386,71 +193,17 @@ static void par_powerup(PROGRAMMER * pgm) /* * 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 */ } - -/* - * 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) +void par_disable(PROGRAMMER * pgm) { 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 @@ -472,8 +225,7 @@ static void par_enable(PROGRAMMER * pgm) ppi_clr(pgm->fd, PPIDATA, pgm->pinno[PPI_AVR_BUFF]); } - -static int par_open(PROGRAMMER * pgm, char * port) +int par_open(PROGRAMMER * pgm, char * port) { 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, @@ -523,8 +275,7 @@ static void par_close(PROGRAMMER * pgm) pgm->fd = -1; } - -static void par_display(PROGRAMMER * pgm, char * p) +void par_display(PROGRAMMER * pgm, char * p) { char vccpins[64]; char buffpins[64]; @@ -574,21 +325,22 @@ void par_initpgm(PROGRAMMER * pgm) { strcpy(pgm->type, "PPI"); - pgm->rdy_led = par_rdy_led; - pgm->err_led = par_err_led; - pgm->pgm_led = par_pgm_led; - pgm->vfy_led = par_vfy_led; - pgm->initialize = par_initialize; + 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 = par_display; pgm->enable = par_enable; pgm->disable = par_disable; pgm->powerup = par_powerup; pgm->powerdown = par_powerdown; - pgm->program_enable = par_program_enable; - pgm->chip_erase = par_chip_erase; - pgm->cmd = par_cmd; + pgm->program_enable = bitbang_program_enable; + pgm->chip_erase = bitbang_chip_erase; + pgm->cmd = bitbang_cmd; pgm->open = par_open; pgm->close = par_close; + + /* this is a parallel port bitbang device */ + pgm->flag = 0; } - - diff --git a/par.h b/par.h index 0aa24fa1..cb1d00a9 100644 --- a/par.h +++ b/par.h @@ -25,6 +25,9 @@ void par_initpgm (PROGRAMMER * pgm); 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 diff --git a/pgm.h b/pgm.h index 75f6cf0d..4482c580 100644 --- a/pgm.h +++ b/pgm.h @@ -83,6 +83,7 @@ typedef struct programmer_t { int (*set_sck_period) (struct programmer_t * pgm, double v); char config_file[PATH_MAX]; /* config file where defined */ int lineno; /* config file line number */ + char flag; /* for private use of the programmer */ } PROGRAMMER; diff --git a/pindefs.h b/pindefs.h index 25dc20f9..9c16ed1c 100644 --- a/pindefs.h +++ b/pindefs.h @@ -35,6 +35,8 @@ enum { PIN_LED_VFY, 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_OFF(fd,pin) ppi_setpin(fd,pin,1) diff --git a/serbb.h b/serbb.h new file mode 100644 index 00000000..0760f6e0 --- /dev/null +++ b/serbb.h @@ -0,0 +1,33 @@ +/* + * avrdude - A Downloader/Uploader for AVR device programmers + * Copyright (C) 2000, 2001, 2002, 2003 Brian S. Dean + * Copyright (C) 2005 Michael Holzt + * + * 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 + + diff --git a/serbb_posix.c b/serbb_posix.c new file mode 100644 index 00000000..04f261bf --- /dev/null +++ b/serbb_posix.c @@ -0,0 +1,271 @@ +/* + * avrdude - A Downloader/Uploader for AVR device programmers + * Copyright (C) 2000, 2001, 2002, 2003 Brian S. Dean + * Copyright (C) 2005 Michael Holzt + * + * 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 +#include +#include +#include +#include +#include +#include +#include + +#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 */ diff --git a/serbb_win32.c b/serbb_win32.c new file mode 100644 index 00000000..79fc9834 --- /dev/null +++ b/serbb_win32.c @@ -0,0 +1,372 @@ +/* + * avrdude - A Downloader/Uploader for AVR device programmers + * Copyright (C) 2003, 2004 Martin J. Thomas + * Copyright (C) 2005 Michael Holzt + * 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, 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 +#include + +#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 */