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