1 /*
2 * avrdude - A Downloader/Uploader for AVR device programmers
3 * Copyright (C) 2000, 2001, 2002, 2003 Brian S. Dean <bsd@bsdhome.com>
4 * Copyright (C) 2005 Michael Holzt <kju-avr@fqdn.org>
5 * Copyright (C) 2006 Joerg Wunsch <j@uriah.heep.sax.de>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program. If not, see <http://www.gnu.org/licenses/>.
19 */
20 /* $Id: serbb_posix.c 1321 2014-06-13 20:07:40Z awachtler $ */
21
22 /*
23 * Posix serial bitbanging interface for avrdude.
24 */
25
26 #if !defined(WIN32NATIVE)
27
28 #include "ac_cfg.h"
29
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <string.h>
33 #include <fcntl.h>
34 #include <unistd.h>
35 #include <errno.h>
36 #include <sys/ioctl.h>
37 #include <termios.h>
38
39 #include "avrdude.h"
40 #include "libavrdude.h"
41
42 #include "bitbang.h"
43 #include "serbb.h"
44
45 #undef DEBUG
46
47 static struct termios oldmode;
48
49 /*
50 serial port/pin mapping
51
52 1 cd <-
53 2 (rxd) <-
54 3 txd ->
55 4 dtr ->
56 5 GND
57 6 dsr <-
58 7 rts ->
59 8 cts <-
60 9 ri <-
61 */
62
63 #define DB9PINS 9
64
65 static int serregbits[DB9PINS + 1] =
66 { 0, TIOCM_CD, 0, 0, TIOCM_DTR, 0, TIOCM_DSR, TIOCM_RTS, TIOCM_CTS, TIOCM_RI };
67
68 #ifdef DEBUG
69 static char *serpins[DB9PINS + 1] =
70 { "NONE", "CD", "RXD", "TXD", "DTR", "GND", "DSR", "RTS", "CTS", "RI" };
71 #endif
72
serbb_setpin(PROGRAMMER * pgm,int pinfunc,int value)73 static int serbb_setpin(PROGRAMMER * pgm, int pinfunc, int value)
74 {
75 unsigned int ctl;
76 int r;
77 int pin = pgm->pinno[pinfunc]; // get its value
78
79 if (pin & PIN_INVERSE)
80 {
81 value = !value;
82 pin &= PIN_MASK;
83 }
84
85 if ( pin < 1 || pin > DB9PINS )
86 return -1;
87
88 #ifdef DEBUG
89 printf("%s to %d\n",serpins[pin],value);
90 #endif
91
92 switch ( pin )
93 {
94 case 3: /* txd */
95 r = ioctl(pgm->fd.ifd, value ? TIOCSBRK : TIOCCBRK, 0);
96 if (r < 0) {
97 perror("ioctl(\"TIOCxBRK\")");
98 return -1;
99 }
100 break;
101
102 case 4: /* dtr */
103 case 7: /* rts */
104 r = ioctl(pgm->fd.ifd, TIOCMGET, &ctl);
105 if (r < 0) {
106 perror("ioctl(\"TIOCMGET\")");
107 return -1;
108 }
109 if ( value )
110 ctl |= serregbits[pin];
111 else
112 ctl &= ~(serregbits[pin]);
113 r = ioctl(pgm->fd.ifd, TIOCMSET, &ctl);
114 if (r < 0) {
115 perror("ioctl(\"TIOCMSET\")");
116 return -1;
117 }
118 break;
119
120 default: /* impossible */
121 return -1;
122 }
123
124 if (pgm->ispdelay > 1)
125 bitbang_delay(pgm->ispdelay);
126
127 return 0;
128 }
129
serbb_getpin(PROGRAMMER * pgm,int pinfunc)130 static int serbb_getpin(PROGRAMMER * pgm, int pinfunc)
131 {
132 unsigned int ctl;
133 unsigned char invert;
134 int r;
135 int pin = pgm->pinno[pinfunc]; // get its value
136
137 if (pin & PIN_INVERSE)
138 {
139 invert = 1;
140 pin &= PIN_MASK;
141 } else
142 invert = 0;
143
144 if ( pin < 1 || pin > DB9PINS )
145 return(-1);
146
147 switch ( pin )
148 {
149 case 2: /* rxd, currently not implemented, FIXME */
150 return(-1);
151
152 case 1: /* cd */
153 case 6: /* dsr */
154 case 8: /* cts */
155 case 9: /* ri */
156 r = ioctl(pgm->fd.ifd, TIOCMGET, &ctl);
157 if (r < 0) {
158 perror("ioctl(\"TIOCMGET\")");
159 return -1;
160 }
161 if ( !invert )
162 {
163 #ifdef DEBUG
164 printf("%s is %d\n",serpins[pin],(ctl & serregbits[pin]) ? 1 : 0 );
165 #endif
166 return ( (ctl & serregbits[pin]) ? 1 : 0 );
167 }
168 else
169 {
170 #ifdef DEBUG
171 printf("%s is %d (~)\n",serpins[pin],(ctl & serregbits[pin]) ? 0 : 1 );
172 #endif
173 return (( ctl & serregbits[pin]) ? 0 : 1 );
174 }
175
176 default: /* impossible */
177 return(-1);
178 }
179 }
180
serbb_highpulsepin(PROGRAMMER * pgm,int pinfunc)181 static int serbb_highpulsepin(PROGRAMMER * pgm, int pinfunc)
182 {
183 int pin = pgm->pinno[pinfunc]; // replace pin name by its value
184
185 if ( (pin & PIN_MASK) < 1 || (pin & PIN_MASK) > DB9PINS )
186 return -1;
187
188 serbb_setpin(pgm, pinfunc, 1);
189 serbb_setpin(pgm, pinfunc, 0);
190
191 return 0;
192 }
193
194
195
serbb_display(PROGRAMMER * pgm,const char * p)196 static void serbb_display(PROGRAMMER *pgm, const char *p)
197 {
198 /* MAYBE */
199 }
200
serbb_enable(PROGRAMMER * pgm)201 static void serbb_enable(PROGRAMMER *pgm)
202 {
203 /* nothing */
204 }
205
serbb_disable(PROGRAMMER * pgm)206 static void serbb_disable(PROGRAMMER *pgm)
207 {
208 /* nothing */
209 }
210
serbb_powerup(PROGRAMMER * pgm)211 static void serbb_powerup(PROGRAMMER *pgm)
212 {
213 /* nothing */
214 }
215
serbb_powerdown(PROGRAMMER * pgm)216 static void serbb_powerdown(PROGRAMMER *pgm)
217 {
218 /* nothing */
219 }
220
serbb_open(PROGRAMMER * pgm,char * port)221 static int serbb_open(PROGRAMMER *pgm, char *port)
222 {
223 struct termios mode;
224 int flags;
225 int r;
226
227 if (bitbang_check_prerequisites(pgm) < 0)
228 return -1;
229
230 /* adapted from uisp code */
231
232 pgm->fd.ifd = open(port, O_RDWR | O_NOCTTY | O_NONBLOCK);
233
234 if (pgm->fd.ifd < 0) {
235 perror(port);
236 return(-1);
237 }
238
239 r = tcgetattr(pgm->fd.ifd, &mode);
240 if (r < 0) {
241 avrdude_message(MSG_INFO, "%s: ", port);
242 perror("tcgetattr");
243 return(-1);
244 }
245 oldmode = mode;
246
247 mode.c_iflag = IGNBRK | IGNPAR;
248 mode.c_oflag = 0;
249 mode.c_cflag = CLOCAL | CREAD | CS8 | B9600;
250 mode.c_cc [VMIN] = 1;
251 mode.c_cc [VTIME] = 0;
252
253 r = tcsetattr(pgm->fd.ifd, TCSANOW, &mode);
254 if (r < 0) {
255 avrdude_message(MSG_INFO, "%s: ", port);
256 perror("tcsetattr");
257 return(-1);
258 }
259
260 /* Clear O_NONBLOCK flag. */
261 flags = fcntl(pgm->fd.ifd, F_GETFL, 0);
262 if (flags == -1)
263 {
264 avrdude_message(MSG_INFO, "%s: Can not get flags: %s\n",
265 progname, strerror(errno));
266 return(-1);
267 }
268 flags &= ~O_NONBLOCK;
269 if (fcntl(pgm->fd.ifd, F_SETFL, flags) == -1)
270 {
271 avrdude_message(MSG_INFO, "%s: Can not clear nonblock flag: %s\n",
272 progname, strerror(errno));
273 return(-1);
274 }
275
276 return(0);
277 }
278
serbb_close(PROGRAMMER * pgm)279 static void serbb_close(PROGRAMMER *pgm)
280 {
281 if (pgm->fd.ifd != -1)
282 {
283 (void)tcsetattr(pgm->fd.ifd, TCSANOW, &oldmode);
284 pgm->setpin(pgm, PIN_AVR_RESET, 1);
285 close(pgm->fd.ifd);
286 }
287 return;
288 }
289
290 const char serbb_desc[] = "Serial port bitbanging";
291
serbb_initpgm(PROGRAMMER * pgm)292 void serbb_initpgm(PROGRAMMER *pgm)
293 {
294 strcpy(pgm->type, "SERBB");
295
296 pgm_fill_old_pins(pgm); // TODO to be removed if old pin data no longer needed
297
298 pgm->rdy_led = bitbang_rdy_led;
299 pgm->err_led = bitbang_err_led;
300 pgm->pgm_led = bitbang_pgm_led;
301 pgm->vfy_led = bitbang_vfy_led;
302 pgm->initialize = bitbang_initialize;
303 pgm->display = serbb_display;
304 pgm->enable = serbb_enable;
305 pgm->disable = serbb_disable;
306 pgm->powerup = serbb_powerup;
307 pgm->powerdown = serbb_powerdown;
308 pgm->program_enable = bitbang_program_enable;
309 pgm->chip_erase = bitbang_chip_erase;
310 pgm->cmd = bitbang_cmd;
311 pgm->cmd_tpi = bitbang_cmd_tpi;
312 pgm->open = serbb_open;
313 pgm->close = serbb_close;
314 pgm->setpin = serbb_setpin;
315 pgm->getpin = serbb_getpin;
316 pgm->highpulsepin = serbb_highpulsepin;
317 pgm->read_byte = avr_read_byte_default;
318 pgm->write_byte = avr_write_byte_default;
319 }
320
321 #endif /* WIN32NATIVE */
322