mirror of
https://github.com/avrdudes/avrdude.git
synced 2026-07-25 19:02:28 +03:00
pgm->type is an internal string that is unknown to users; in fact, even developers don't necessarily know it well. This commit replaces references to pgm->type to the more specific -c programmer (that the user provided).
322 lines
7.5 KiB
C
322 lines
7.5 KiB
C
/*
|
|
* avrdude - A Downloader/Uploader for AVR device programmers
|
|
* Copyright (C) 2000, 2001, 2002, 2003 Brian S. Dean <bsd@bdmicro.com>
|
|
* Copyright (C) 2005 Juliane Holzt <avrdude@juliane.holzt.de>
|
|
* Copyright (C) 2006 Joerg Wunsch <j@uriah.heep.sax.de>
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
// Posix serial bitbanging interface for avrdude
|
|
|
|
#if !defined(WIN32)
|
|
#include <ac_cfg.h>
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <fcntl.h>
|
|
#include <unistd.h>
|
|
#include <errno.h>
|
|
#include <sys/ioctl.h>
|
|
#include <termios.h>
|
|
|
|
#include "avrdude.h"
|
|
#include "libavrdude.h"
|
|
|
|
#include "bitbang.h"
|
|
#include "serbb.h"
|
|
|
|
#undef DEBUG
|
|
|
|
struct pdata {
|
|
struct termios oldmode;
|
|
};
|
|
|
|
// Use private programmer data as if they were a global structure my
|
|
#define my (*(struct pdata *)(pgm->cookie))
|
|
|
|
/*
|
|
* Serial port/pin mapping
|
|
*
|
|
* 1 cd <-
|
|
* 2 (rxd) <-
|
|
* 3 txd ->
|
|
* 4 dtr ->
|
|
* 5 GND
|
|
* 6 dsr <-
|
|
* 7 rts ->
|
|
* 8 cts <-
|
|
* 9 ri <-
|
|
*
|
|
*/
|
|
|
|
#define DB9PINS 9
|
|
|
|
static const int serregbits[DB9PINS + 1] = {
|
|
0, TIOCM_CD, 0, 0, TIOCM_DTR, 0, TIOCM_DSR, TIOCM_RTS, TIOCM_CTS, TIOCM_RI
|
|
};
|
|
|
|
#ifdef DEBUG
|
|
static const char *const serpins[DB9PINS + 1] = {
|
|
"NONE", "CD", "RXD", "TXD", "DTR", "GND", "DSR", "RTS", "CTS", "RI"
|
|
};
|
|
#endif
|
|
|
|
static int serbb_setpin(const PROGRAMMER *pgm, int pinfunc, int value) {
|
|
unsigned int ctl;
|
|
int r;
|
|
|
|
if(pinfunc < 0 || pinfunc >= N_PINS)
|
|
return -1;
|
|
|
|
int pin = pgm->pinno[pinfunc]; // Get its value
|
|
|
|
if(pin & PIN_INVERSE) {
|
|
value = !value;
|
|
pin &= PIN_MASK;
|
|
}
|
|
|
|
if(pin < 1 || pin > DB9PINS)
|
|
return -1;
|
|
|
|
#ifdef DEBUG
|
|
msg_notice("%s to %d\n", serpins[pin], value);
|
|
#endif
|
|
|
|
switch(pin) {
|
|
case 3: // txd
|
|
r = ioctl(pgm->fd.ifd, value? TIOCSBRK: TIOCCBRK, 0);
|
|
if(r < 0) {
|
|
pmsg_ext_error("ioctl(\"TIOCxBRK\"): %s\n", strerror(errno));
|
|
return -1;
|
|
}
|
|
break;
|
|
|
|
case 4: // dtr
|
|
case 7: // rts
|
|
r = ioctl(pgm->fd.ifd, TIOCMGET, &ctl);
|
|
if(r < 0) {
|
|
pmsg_ext_error("ioctl(\"TIOCMGET\"): %s\n", strerror(errno));
|
|
return -1;
|
|
}
|
|
if(value)
|
|
ctl |= serregbits[pin];
|
|
else
|
|
ctl &= ~(serregbits[pin]);
|
|
r = ioctl(pgm->fd.ifd, TIOCMSET, &ctl);
|
|
if(r < 0) {
|
|
pmsg_ext_error("ioctl(\"TIOCMSET\"): %s\n", strerror(errno));
|
|
return -1;
|
|
}
|
|
break;
|
|
|
|
default: // Impossible
|
|
return -1;
|
|
}
|
|
|
|
if(pgm->ispdelay > 1)
|
|
bitbang_delay(pgm->ispdelay);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int serbb_getpin(const PROGRAMMER *pgm, int pinfunc) {
|
|
unsigned int ctl;
|
|
unsigned char invert;
|
|
int r;
|
|
|
|
if(pinfunc < 0 || pinfunc >= N_PINS)
|
|
return -1;
|
|
|
|
int pin = pgm->pinno[pinfunc]; // Get its value
|
|
|
|
if(pin & PIN_INVERSE) {
|
|
invert = 1;
|
|
pin &= PIN_MASK;
|
|
} else
|
|
invert = 0;
|
|
|
|
if(pin < 1 || pin > DB9PINS)
|
|
return (-1);
|
|
|
|
switch(pin) {
|
|
case 2: // rxd, currently not implemented, FIXME
|
|
return (-1);
|
|
|
|
case 1: // cd
|
|
case 6: // dsr
|
|
case 8: // cts
|
|
case 9: // ri
|
|
r = ioctl(pgm->fd.ifd, TIOCMGET, &ctl);
|
|
if(r < 0) {
|
|
pmsg_ext_error("ioctl(\"TIOCMGET\"): %s\n", strerror(errno));
|
|
return -1;
|
|
}
|
|
if(!invert) {
|
|
|
|
#ifdef DEBUG
|
|
msg_notice("%s is %d\n", serpins[pin], ctl & serregbits[pin]? 1: 0);
|
|
#endif
|
|
|
|
return ctl & serregbits[pin]? 1: 0;
|
|
} else {
|
|
|
|
#ifdef DEBUG
|
|
msg_notice("%s is %d (~)\n", serpins[pin], ctl & serregbits[pin]? 0: 1);
|
|
#endif
|
|
|
|
return ctl & serregbits[pin]? 0: 1;
|
|
}
|
|
|
|
default: // Impossible
|
|
return (-1);
|
|
}
|
|
}
|
|
|
|
static int serbb_highpulsepin(const PROGRAMMER *pgm, int pinfunc) {
|
|
if(pinfunc < 0 || pinfunc >= N_PINS)
|
|
return -1;
|
|
|
|
int pin = pgm->pinno[pinfunc]; // Replace pin name by its value
|
|
|
|
if((pin & PIN_MASK) < 1 || (pin & PIN_MASK) > DB9PINS)
|
|
return -1;
|
|
|
|
serbb_setpin(pgm, pinfunc, 1);
|
|
serbb_setpin(pgm, pinfunc, 0);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static void serbb_display(const PROGRAMMER *pgm, const char *p) {
|
|
}
|
|
|
|
static void serbb_enable(PROGRAMMER *pgm, const AVRPART *p) {
|
|
}
|
|
|
|
static void serbb_disable(const PROGRAMMER *pgm) {
|
|
}
|
|
|
|
static void serbb_powerup(const PROGRAMMER *pgm) {
|
|
}
|
|
|
|
static void serbb_powerdown(const PROGRAMMER *pgm) {
|
|
}
|
|
|
|
static int serbb_open(PROGRAMMER *pgm, const char *port) {
|
|
struct termios mode;
|
|
int flags;
|
|
int r;
|
|
|
|
if(pgm->bitclock)
|
|
pmsg_warning("-c %s does not support adjustable bitclock speed using -B; use -i instead\n", pgmid);
|
|
|
|
if(bitbang_check_prerequisites(pgm) < 0)
|
|
return -1;
|
|
|
|
// Adapted from uisp code
|
|
|
|
pgm->fd.ifd = open(port, O_RDWR | O_NOCTTY | O_NONBLOCK);
|
|
|
|
if(pgm->fd.ifd < 0) {
|
|
pmsg_ext_error("%s: %s\n", port, strerror(errno));
|
|
return (-1);
|
|
}
|
|
|
|
r = tcgetattr(pgm->fd.ifd, &mode);
|
|
if(r < 0) {
|
|
pmsg_ext_error("%s, tcgetattr(): %s\n", port, strerror(errno));
|
|
return (-1);
|
|
}
|
|
my.oldmode = mode;
|
|
|
|
mode.c_iflag = IGNBRK | IGNPAR;
|
|
mode.c_oflag = 0;
|
|
mode.c_cflag = CLOCAL | CREAD | CS8 | B9600;
|
|
mode.c_cc[VMIN] = 1;
|
|
mode.c_cc[VTIME] = 0;
|
|
|
|
r = tcsetattr(pgm->fd.ifd, TCSANOW, &mode);
|
|
if(r < 0) {
|
|
pmsg_ext_error("%s, tcsetattr(): %s", port, strerror(errno));
|
|
return (-1);
|
|
}
|
|
|
|
// Clear O_NONBLOCK flag
|
|
flags = fcntl(pgm->fd.ifd, F_GETFL, 0);
|
|
if(flags == -1) {
|
|
pmsg_ext_error("cannot get flags: %s\n", strerror(errno));
|
|
return (-1);
|
|
}
|
|
flags &= ~O_NONBLOCK;
|
|
if(fcntl(pgm->fd.ifd, F_SETFL, flags) == -1) {
|
|
pmsg_ext_error("cannot clear nonblock flag: %s\n", strerror(errno));
|
|
return (-1);
|
|
}
|
|
|
|
return (0);
|
|
}
|
|
|
|
static void serbb_close(PROGRAMMER *pgm) {
|
|
if(pgm->fd.ifd != -1) {
|
|
(void) tcsetattr(pgm->fd.ifd, TCSANOW, &my.oldmode);
|
|
pgm->setpin(pgm, PIN_AVR_RESET, 1);
|
|
close(pgm->fd.ifd);
|
|
}
|
|
return;
|
|
}
|
|
|
|
static void serbb_setup(PROGRAMMER *pgm) {
|
|
pgm->cookie = mmt_malloc(sizeof(struct pdata));
|
|
}
|
|
|
|
static void serbb_teardown(PROGRAMMER *pgm) {
|
|
mmt_free(pgm->cookie);
|
|
pgm->cookie = NULL;
|
|
}
|
|
|
|
const char serbb_desc[] = "Serial port bitbanging";
|
|
|
|
void serbb_initpgm(PROGRAMMER *pgm) {
|
|
strcpy(pgm->type, "SERBB");
|
|
|
|
pgm_fill_old_pins(pgm); // TODO to be removed if old pin data no longer needed
|
|
|
|
pgm->setup = serbb_setup;
|
|
pgm->teardown = serbb_teardown;
|
|
pgm->rdy_led = bitbang_rdy_led;
|
|
pgm->err_led = bitbang_err_led;
|
|
pgm->pgm_led = bitbang_pgm_led;
|
|
pgm->vfy_led = bitbang_vfy_led;
|
|
pgm->initialize = bitbang_initialize;
|
|
pgm->display = serbb_display;
|
|
pgm->enable = serbb_enable;
|
|
pgm->disable = serbb_disable;
|
|
pgm->powerup = serbb_powerup;
|
|
pgm->powerdown = serbb_powerdown;
|
|
pgm->program_enable = bitbang_program_enable;
|
|
pgm->chip_erase = bitbang_chip_erase;
|
|
pgm->cmd = bitbang_cmd;
|
|
pgm->cmd_tpi = bitbang_cmd_tpi;
|
|
pgm->open = serbb_open;
|
|
pgm->close = serbb_close;
|
|
pgm->setpin = serbb_setpin;
|
|
pgm->getpin = serbb_getpin;
|
|
pgm->highpulsepin = serbb_highpulsepin;
|
|
pgm->read_byte = avr_read_byte_default;
|
|
pgm->write_byte = avr_write_byte_default;
|
|
}
|
|
#endif // WIN32
|