1 /*
2 * port.c - All port related vrflash functions Copyright (C) 2001 Jeff
3 * Carneal
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the
7 * Free Software Foundation; either version 2 of the License, or (at your
8 * option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 */
19
20 #include "config.h"
21 #include <stdio.h>
22 #include <unistd.h>
23 #include <sys/time.h>
24 #include <sys/types.h>
25 #include <sys/stat.h>
26 #include <fcntl.h>
27
28 #ifdef HAVE_TERMIO_H
29 #include <termio.h>
30 #else
31 #include <termios.h>
32 #endif
33
34 #include <string.h>
35 #include <ctype.h>
36 #ifdef HAVE_LOW_LATENCY
37 #include <linux/serial.h>
38 #endif
39 #include "main.h"
40 #include "port.h"
41 #include "xmodem.h"
42 #include "vrerror.h"
43
44 const char *prompt1 = "PMON> ";
45 const char *prompt2 = "PMram>"; // used on all 16MB ram models before 2002/10/23
46
47 extern int do_portlog;
48
49 #ifdef HAVE_LOW_LATENCY
50 int
port_lowlatency(char * filestr,int fd)51 port_lowlatency(char *filestr, int fd)
52 {
53 struct serial_struct serinfo;
54
55 if (ioctl (fd, TIOCGSERIAL, &serinfo) < 0)
56 {
57 vr_warning ("Warning: Cannot get linux serial options");
58 return fd;
59 }
60 serinfo.flags |= ASYNC_LOW_LATENCY;
61 if (ioctl (fd, TIOCSSERIAL, &serinfo) < 0)
62 {
63 vr_warning ("Warning: Cannot set linux serial options");
64 return fd;
65 }
66
67 /*
68 * Major hack. For some reason the LOW_LATENCY flag
69 * will not set on an open port. You have to close
70 * and reopen port to make it work. I looked
71 * for a TIOC ioctl flag that would override this
72 * but couldn't find it. Let me know if you know
73 * of one, cuz I hate this code
74 */
75 close (fd);
76 if ((fd = open (filestr, O_RDWR | O_NOCTTY | O_NDELAY)) < 0)
77 return -1;
78
79 if (ioctl (fd, TIOCGSERIAL, &serinfo) < 0)
80 {
81 vr_warning ("Warning: Cannot get linux serial options");
82 return fd;
83 }
84 serinfo.flags |= ASYNC_LOW_LATENCY;
85 if (ioctl (fd, TIOCSSERIAL, &serinfo) < 0)
86 {
87 vr_warning ("Warning: Cannot set linux serial options");
88 return fd;
89 }
90 return fd;
91 }
92 #endif
93
94 /*
95 * Returns the file descriptor on success or -1 on error.
96 */
97 int
port_open(char * filestr)98 port_open (char *filestr)
99 {
100 int fd;
101
102 if ((fd = open (filestr, O_RDWR | O_NOCTTY | O_NDELAY)) < 0)
103 return -1;
104
105 #ifdef HAVE_LOW_LATENCY
106 if ((fd=port_lowlatency(filestr, fd)) < 0)
107 return -1;
108 #endif
109
110 fcntl (fd, F_SETFL, 0);
111 return (fd);
112 }
113
114 void
port_init(int fd)115 port_init (int fd)
116 {
117 struct termios options;
118
119 /*
120 * Get the port options
121 */
122 if (tcgetattr (fd, &options) < 0)
123 vr_error ("Error: Cannot get serial options");
124
125 /*
126 * Set to 115200 bps
127 */
128 cfsetispeed (&options, B115200);
129 cfsetospeed (&options, B115200);
130
131 /*
132 * Set to 8N1
133 */
134 options.c_cflag |= (CLOCAL | CREAD);
135 options.c_cflag &= ~PARENB;
136 options.c_cflag &= ~CSTOPB;
137 options.c_cflag &= ~CSIZE;
138 options.c_cflag |= CS8;
139
140 /*
141 * Hardware FC
142 */
143 #ifdef HAVE_CRTSCTS
144 options.c_cflag |= CRTSCTS;
145 #elif HAVE_NEWRTSCTS
146 options.c_cflag |= CNEW_RTSCTS;
147 #endif
148 options.c_iflag &= ~(IXON | IXOFF | IXANY);
149
150 /*
151 * Raw inputing. Disable local echo,
152 * canonical input and signals
153 */
154 options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);
155
156 /*
157 * Use parity checking
158 */
159 options.c_iflag |= (INPCK | ISTRIP);
160
161 /*
162 * Raw output
163 */
164 options.c_oflag &= ~OPOST;
165
166 /*
167 * Set 5s timeout value
168 */
169 options.c_cc[VMIN] = 0;
170 options.c_cc[VTIME] = TIMEOUT;
171 /*
172 * options.c_cc[VEOF] = 1; options.c_cc[VEOL] = 0; * no wait *
173 * serinfo.flags |= ASYNC_LOW_LATENCY;
174 */
175
176 /*
177 * Set the new options for the port...
178 */
179
180 if (tcsetattr (fd, TCSANOW, &options) < 0)
181 vr_error ("Error: Cannot set serial options");
182
183 }
184
185 void
port_send(int fd,char * str,int len,int log)186 port_send (int fd, char *str, int len, int log)
187 {
188 int wlen = 0;
189 int ret = 0;
190 int i;
191 fd_set fds;
192 struct timeval tv;
193
194 for (i = 0; i < RETRIES; i++)
195 {
196 FD_ZERO (&fds);
197 FD_SET (fd, &fds);
198 tv.tv_sec = TIMEOUT;
199 tv.tv_usec = 0;
200 if ((ret = select (fd + 1, NULL, &fds, NULL, &tv)) > 0)
201 {
202 if ((wlen = write (fd, str, len)) < 0)
203 {
204 vr_error ("Error: port_send unable to write to serial port");
205 }
206 else if (wlen < len)
207 {
208 vr_error ("Error: port_send to write full buffer to serial port");
209 }
210 else
211 {
212 if (do_portlog && log)
213 {
214 port_log (str, len);
215 }
216 return;
217 }
218 }
219 }
220 vr_error ("Error: port_send timeout writing to port");
221 }
222
223
224 int
port_readline(int fd,char * buf)225 port_readline (int fd, char *buf)
226 {
227 char inchar;
228 int i = 0;
229 int index = 0;
230 int ret = 0;
231 fd_set fds;
232 struct timeval tv;
233
234 memset (buf, 0, BUFSIZE);
235
236 for (i = 0; i < RETRIES; i++)
237 {
238 FD_ZERO (&fds);
239 FD_SET (fd, &fds);
240 tv.tv_sec = TIMEOUT;
241 tv.tv_usec = 0;
242 if ((ret = select (fd + 1, &fds, NULL, NULL, &tv)) > 0)
243 {
244 while (read (fd, (void *) &inchar, 1) >= 0)
245 {
246 /*
247 * Skip '\n' and '\n' at beginning
248 * ie, blank lines
249 */
250 if ((!index)
251 && ((inchar == '\n') || (inchar == '\r')))
252 {
253 continue;
254 }
255 if (strstr (buf, prompt1)
256 || strstr (buf, prompt2)
257 || (inchar == '\n') || (inchar == '\r'))
258 {
259 if (do_portlog)
260 {
261 port_log (buf, strlen (buf));
262 }
263 return 0;
264 }
265 buf[index] = inchar;
266 index++;
267 if (index >= BUFSIZE)
268 {
269 vr_error ("Error: port_readline line too long");
270 }
271 }
272 return -1;
273 }
274 }
275 return -1;
276 }
277
278 void
port_readflush(int fd)279 port_readflush (int fd)
280 {
281 char buf;
282 char logbuf[BUFSIZE];
283 fd_set fds;
284 int i = 0;
285 struct timeval tv;
286
287 memset (logbuf, 0, BUFSIZE);
288
289 do
290 {
291 FD_ZERO (&fds);
292 FD_SET (fd, &fds);
293 /*
294 * Short timeout since we're
295 * flushing not reading
296 */
297 tv.tv_sec = 0;
298 tv.tv_usec = UTIMEOUT;
299 if (read (fd, (void *) &buf, 1) < 0)
300 {
301 vr_error ("Error: port_readflush failed to read byte");
302 }
303 if ((i < BUFSIZE) && (buf != '\r'))
304 {
305 logbuf[i] = buf;
306 i++;
307 }
308 }
309 while (select (fd + 1, &fds, NULL, NULL, &tv));
310 if (do_portlog)
311 {
312 port_log (logbuf, strlen (logbuf));
313 }
314 }
315
316 void
port_flush(int fd)317 port_flush (int fd)
318 {
319 /*
320 * char buf[3]; snprintf(buf, 3, "%c\r", EOF); buf[2]=0; port_send(fd,
321 * buf);
322 */
323 port_send (fd, "\r\r", 2, PORTLOG);
324 port_readflush (fd);
325 port_send (fd, "\r", 1, PORTLOG);
326 }
327
328 void
port_getpmon(int fd,char * buf)329 port_getpmon (int fd, char *buf)
330 {
331 fprintf (stderr, "Looking for PMON prompt...");
332 port_flush (fd);
333 if (port_readline (fd, buf) < 0)
334 vr_error ("Error: port_getpmon timed out reading from port");
335 fprintf (stderr, "done\n");
336 }
337
338 void
port_log(char * str,int len)339 port_log (char *str, int len)
340 {
341 int fd;
342 int i;
343 int index = 0;
344 char logbuf[BUFSIZE];
345
346 memset (logbuf, 0, BUFSIZE);
347 for (i = 0; (i < len) && (i < BUFSIZE); i++)
348 {
349 if (isprint (str[i]) || (str[i] == '\n'))
350 {
351 logbuf[index] = str[i];
352 index++;
353 }
354 }
355 if (!index)
356 return;
357
358 if (logbuf[index] != '\n')
359 logbuf[index] = '\n';
360 fd = open (LOGFILE, O_WRONLY | O_APPEND | O_NDELAY, 0);
361 if (fd)
362 {
363 write (fd, &logbuf, strlen (logbuf));
364 close (fd);
365 }
366 }
367