Files
avrdude/src/serbb_posix.c
stefanrueger 46893bed3d Sharpen warning messages
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).
2025-05-09 16:22:25 +02:00

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