1 /*
2  * sysdep1.c	system dependant routines.
3  *
4  *		m_dtrtoggle	- dropt dtr and raise it again
5  *		m_break		- send BREAK signal
6  *		m_getdcd	- get modem dcd status
7  *		m_setdcd	- set modem dcd status
8  *		m_savestate	- save modem state
9  *		m_restorestate	- restore saved modem state
10  *		m_nohang	- tell driver not to hang up at DTR drop
11  *		m_hupcl		- set hangup on close on/off
12  *		m_setparms	- set speed, parity, bits and stopbits
13  *		m_readchk	- see if there is input waiting.
14  *		m_wait		- wait for child to finish. Sysdep. too.
15  *
16  *		If it's possible, Posix termios are preferred.
17  *
18  *		This file is part of the minicom communications package,
19  *		Copyright 1991-1995 Miquel van Smoorenburg.
20  *
21  *		This program is free software; you can redistribute it and/or
22  *		modify it under the terms of the GNU General Public License
23  *		as published by the Free Software Foundation; either version
24  *		2 of the License, or (at your option) any later version.
25  *
26  *  You should have received a copy of the GNU General Public License along
27  *  with this program; if not, write to the Free Software Foundation, Inc.,
28  *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
29  *
30  *   jl  23.06.97  adjustable DTR downtime
31  */
32 #ifdef HAVE_CONFIG_H
33 #include <config.h>
34 #endif
35 
36 #include "sysdep.h"
37 #include "minicom.h"
38 
39 /* Set hardware flow control. */
m_sethwf(int fd,int on)40 void m_sethwf(int fd, int on)
41 {
42 #ifdef POSIX_TERMIOS
43   struct termios tty;
44 #endif
45 
46 #ifdef USE_SOCKET
47   if (portfd_is_socket)
48 	return;
49 #endif
50 
51 #ifdef POSIX_TERMIOS
52   tcgetattr(fd, &tty);
53   if (on)
54     tty.c_cflag |= CRTSCTS;
55   else
56     tty.c_cflag &= ~CRTSCTS;
57   tcsetattr(fd, TCSANOW, &tty);
58 #endif
59 }
60 
61 /* Set RTS line. Sometimes dropped. Linux specific? */
m_setrts(int fd)62 static void m_setrts(int fd)
63 {
64 #ifdef USE_SOCKET
65   if (portfd_is_socket)
66     return;
67 #endif
68 #if defined(TIOCM_RTS) && defined(TIOCMGET)
69   {
70     int mcs=0;
71 
72     ioctl(fd, TIOCMGET, &mcs);
73     mcs |= TIOCM_RTS;
74     ioctl(fd, TIOCMSET, &mcs);
75   }
76 #endif
77 }
78 
79 /*
80  * Drop DTR line and raise it again.
81  */
m_dtrtoggle(int fd,int sec)82 void m_dtrtoggle(int fd, int sec)
83 {
84 #ifdef USE_SOCKET
85   if (portfd_is_socket)
86     return;
87 #endif
88   {
89 #ifdef TIOCSDTR
90     /* Use the ioctls meant for this type of thing. */
91     ioctl(fd, TIOCCDTR, 0);
92     if (sec>0) {
93       sleep(sec);
94       ioctl(fd, TIOCSDTR, 0);
95     }
96 
97 #else /* TIOCSDTR */
98 #  if defined (POSIX_TERMIOS)
99 
100     /* Posix - set baudrate to 0 and back */
101     struct termios tty, old;
102 
103     tcgetattr(fd, &tty);
104     tcgetattr(fd, &old);
105     cfsetospeed(&tty, B0);
106     cfsetispeed(&tty, B0);
107     tcsetattr(fd, TCSANOW, &tty);
108     if (sec > 0) {
109       sleep(sec);
110       tcsetattr(fd, TCSANOW, &old);
111     }
112 
113 #  else /* POSIX */
114 #    ifdef _V7
115 
116     /* Just drop speed to 0 and back to normal again */
117     struct sgttyb sg, ng;
118 
119     ioctl(fd, TIOCGETP, &sg);
120     ioctl(fd, TIOCGETP, &ng);
121 
122     ng.sg_ispeed = ng.sg_ospeed = 0;
123     ioctl(fd, TIOCSETP, &ng);
124     if (sec > 0) {
125       sleep(sec);
126       ioctl(fd, TIOCSETP, &sg);
127     }
128 
129 #    endif /* _V7 */
130 #  endif /* POSIX */
131 #endif /* TIOCSDTR */
132   }
133 }
134 
135 /*
136  * Send a break
137  */
m_break(int fd)138 void m_break(int fd)
139 {
140 #ifdef USE_SOCKET
141   if (portfd_is_socket)
142     return;
143 #endif
144 #ifdef POSIX_TERMIOS
145   tcsendbreak(fd, 0);
146 #else
147 #  ifdef _V7
148 #    ifndef TIOCSBRK
149   {
150     struct sgttyb sg, ng;
151 
152     ioctl(fd, TIOCGETP, &sg);
153     ioctl(fd, TIOCGETP, &ng);
154     ng.sg_ispeed = ng.sg_ospeed = B110;
155     ng.sg_flags = BITS8 | RAW;
156     ioctl(fd, TIOCSETP, &ng);
157     write(fd, "\0\0\0\0\0\0\0\0\0\0", 10);
158     ioctl(fd, TIOCSETP, &sg);
159   }
160 #    else
161   ioctl(fd, TIOCSBRK, 0);
162   sleep(1);
163   ioctl(fd, TIOCCBRK, 0);
164 #    endif
165 #  endif
166 #endif
167 }
168 
169 /*
170  * Get the dcd status
171  */
m_getdcd(int fd)172 int m_getdcd(int fd)
173 {
174 #ifdef USE_SOCKET
175   if (portfd_is_socket) {
176     if (portfd_is_connected)
177       return 1;
178     /* we are not connected so this may be a good point to try to connect */
179     term_socket_connect();
180     return portfd_is_connected;
181   }
182 #endif
183 #ifdef TIOCMODGET
184   {
185     int mcs = 0;
186 
187     if (ioctl(fd, TIOCMODGET, &mcs) < 0)
188       return -1;
189     return mcs & TIOCM_CAR ? 1 : 0;
190   }
191 #else
192   (void)fd;
193   return 0; /* Impossible!! (eg. Coherent) */
194 #endif
195 }
196 
197 /* Variables to save states in */
198 #ifdef POSIX_TERMIOS
199 static struct termios savetty;
200 static int m_word;
201 #else
202 #  if defined (_BSD43) || defined (_V7)
203 static struct sgttyb sg;
204 static struct tchars tch;
205 static int lsw;
206 static int m_word;
207 #  endif
208 #endif
209 
210 /*
211  * Save the state of a port
212  */
m_savestate(int fd)213 void m_savestate(int fd)
214 {
215 #ifdef USE_SOCKET
216   if (portfd_is_socket)
217     return;
218 #endif
219 #ifdef POSIX_TERMIOS
220   tcgetattr(fd, &savetty);
221 #else
222 #  if defined(_BSD43) || defined(_V7)
223   ioctl(fd, TIOCGETP, &sg);
224   ioctl(fd, TIOCGETC, &tch);
225 #  endif
226 #  ifdef _BSD43
227   ioctl(fd, TIOCLGET, &lsw);
228 #  endif
229 #endif
230 #ifdef TIOCMGET
231   ioctl(fd, TIOCMGET, &m_word);
232 #endif
233 }
234 
235 /*
236  * Restore the state of a port
237  */
m_restorestate(int fd)238 void m_restorestate(int fd)
239 {
240 #ifdef USE_SOCKET
241   if (portfd_is_socket)
242     return;
243 #endif
244 #ifdef POSIX_TERMIOS
245   tcsetattr(fd, TCSANOW, &savetty);
246 #else
247 #  if defined(_BSD43) || defined(_V7)
248   ioctl(fd, TIOCSETP, &sg);
249   ioctl(fd, TIOCSETC, &tch);
250 #  endif
251 #  ifdef _BSD43
252   ioctl(fd, TIOCLSET, &lsw);
253 #  endif
254 #endif
255 #ifdef TIOCMSET
256   ioctl(fd, TIOCMSET, &m_word);
257 #endif
258 }
259 
260 /*
261  * Set the line status so that it will not kill our process
262  * if the line hangs up.
263  */
264 /*ARGSUSED*/
m_nohang(int fd)265 void m_nohang(int fd)
266 {
267 #ifdef USE_SOCKET
268   if (portfd_is_socket)
269     return;
270 #endif
271   {
272 #ifdef POSIX_TERMIOS
273     struct termios sgg;
274 
275     tcgetattr(fd, &sgg);
276     sgg.c_cflag |= CLOCAL;
277     tcsetattr(fd, TCSANOW, &sgg);
278 #else
279 #  if defined (_BSD43) && defined(LNOHANG)
280     int lsw;
281 
282     ioctl(fd, TIOCLGET, &lsw);
283     lsw |= LNOHANG;
284     ioctl(fd, TIOCLSET, &lsw);
285 #  endif
286 #endif
287   }
288 }
289 
290 /*
291  * Set hangup on close on/off.
292  */
m_hupcl(int fd,int on)293 void m_hupcl(int fd, int on)
294 {
295 #ifdef USE_SOCKET
296   if (portfd_is_socket)
297     return;
298 #endif
299   /* Eh, I don't know how to do this under BSD (yet..) */
300 #ifdef POSIX_TERMIOS
301   {
302     struct termios sgg;
303 
304     tcgetattr(fd, &sgg);
305     if (on)
306       sgg.c_cflag |= HUPCL;
307     else
308       sgg.c_cflag &= ~HUPCL;
309     tcsetattr(fd, TCSANOW, &sgg);
310   }
311 #endif
312 }
313 
314 /*
315  * See if there is input waiting.
316  * returns: 0=nothing, >0=something, -1=can't.
317  */
m_readchk(int fd)318 int m_readchk(int fd)
319 {
320 #ifdef FIONREAD
321   long i = -1;
322 
323   ioctl(fd, FIONREAD, &i);
324   return (int)i;
325 #else
326 #  if defined(F_GETFL) && defined(O_NDELAY)
327   int i, old;
328   char c;
329 
330   old = fcntl(fd, F_GETFL, 0);
331   fcntl(fd, F_SETFL, old | O_NDELAY);
332   i = read(fd, &c, 1);
333   fcntl(fd, F_SETFL, old);
334 
335   return i;
336 #  else
337   return -1;
338 #  endif
339 #endif
340 }
341 
342 /*
343  * Get maximum speed.
344  * Returns maximum speed in baud
345  */
m_getmaxspd(void)346 unsigned m_getmaxspd(void)
347 {
348 #if defined(B4000000)
349   return 4000000;
350 #elif defined(B3500000)
351   return 3500000;
352 #elif defined(B3000000)
353   return 3000000;
354 #elif defined(B2500000)
355   return 2500000;
356 #elif defined(B2000000)
357   return 2000000;
358 #elif defined(B1500000)
359   return 1500000;
360 #elif defined(B1152000)
361   return 1152000;
362 #elif defined(B1000000)
363   return 1000000;
364 #elif defined(B921600)
365   return 921600;
366 #elif defined(B576000)
367   return 576000;
368 #elif defined(B500000)
369   return 500000;
370 #elif defined(B460800)
371   return 460800;
372 #elif defined(B230400)
373   return 230400;
374 #elif defined(B115200)
375   return 115200;
376 #elif defined(B57600)
377   return 57600;
378 #elif defined(B38400)
379   return 38400;
380 #elif defined(EXTB)
381   return 38400;
382 #elif defined(B19200)
383   return 19200;
384 #elif defined(EXTA)
385   return 19200;
386 #else
387   return 9600;
388 #endif
389 }
390 
391 /*
392  * Set baudrate, parity and number of bits.
393  */
m_setparms(int fd,char * baudr,char * par,char * bits,char * stopb,int hwf,int swf)394 void m_setparms(int fd, char *baudr, char *par, char *bits, char *stopb,
395                 int hwf, int swf)
396 {
397   int spd = -1;
398   int newbaud;
399   int bit = bits[0];
400 
401 #ifdef POSIX_TERMIOS
402   struct termios tty;
403 #else /* POSIX_TERMIOS */
404   struct sgttyb tty;
405 #endif /* POSIX_TERMIOS */
406 
407 #ifdef USE_SOCKET
408   if (portfd_is_socket)
409     return;
410 #endif
411 
412 #ifdef POSIX_TERMIOS
413   tcgetattr(fd, &tty);
414 #else /* POSIX_TERMIOS */
415   ioctl(fd, TIOCGETP, &tty);
416 #endif /* POSIX_TERMIOS */
417 
418 
419   /* We generate mark and space parity ourself. */
420   if (bit == '7' && (par[0] == 'M' || par[0] == 'S'))
421     bit = '8';
422 
423   /* Check if 'baudr' is really a number */
424   if ((newbaud = (atol(baudr) / 100)) == 0 && baudr[0] != '0')
425     newbaud = -1;
426 
427   switch (newbaud) {
428     case 0:
429 #ifdef B0
430       spd = B0;
431 #else
432       spd = 0;
433 #endif
434       break;
435     case 3:	spd = B300;	break;
436     case 6:	spd = B600;	break;
437     case 12:	spd = B1200;	break;
438     case 24:	spd = B2400;	break;
439     case 48:	spd = B4800;	break;
440     case 96:	spd = B9600;	break;
441 #ifdef B19200
442     case 192:	spd = B19200;	break;
443 #else /* B19200 */
444 #  ifdef EXTA
445     case 192:	spd = EXTA;	break;
446 #   else /* EXTA */
447     case 192:	spd = B9600;	break;
448 #   endif /* EXTA */
449 #endif	 /* B19200 */
450 #ifdef B38400
451     case 384:	spd = B38400;	break;
452 #else /* B38400 */
453 #  ifdef EXTB
454     case 384:	spd = EXTB;	break;
455 #   else /* EXTB */
456     case 384:	spd = B9600;	break;
457 #   endif /* EXTB */
458 #endif	 /* B38400 */
459 #ifdef B57600
460     case 576:	spd = B57600;	break;
461 #endif
462 #ifdef B115200
463     case 1152:	spd = B115200;	break;
464 #endif
465 #ifdef B230400
466     case 2304:	spd = B230400;	break;
467 #endif
468 #ifdef B460800
469     case 4608: spd = B460800; break;
470 #endif
471 #ifdef B500000
472     case 5000: spd = B500000; break;
473 #endif
474 #ifdef B576000
475     case 5760: spd = B576000; break;
476 #endif
477 #ifdef B921600
478     case 9216: spd = B921600; break;
479 #endif
480 #ifdef B1000000
481     case 10000: spd = B1000000; break;
482 #endif
483 #ifdef B1152000
484     case 11520: spd = B1152000; break;
485 #endif
486 #ifdef B1500000
487     case 15000: spd = B1500000; break;
488 #endif
489 #ifdef B2000000
490     case 20000: spd = B2000000; break;
491 #endif
492 #ifdef B2500000
493     case 25000: spd = B2500000; break;
494 #endif
495 #ifdef B3000000
496     case 30000: spd = B3000000; break;
497 #endif
498 #ifdef B3500000
499     case 35000: spd = B3500000; break;
500 #endif
501 #ifdef B4000000
502     case 40000: spd = B4000000; break;
503 #endif
504   }
505 
506 #if defined (_BSD43) && !defined(POSIX_TERMIOS)
507   if (spd != -1)
508     tty.sg_ispeed = tty.sg_ospeed = spd;
509   /* Number of bits is ignored */
510 
511   tty.sg_flags = RAW | TANDEM;
512   if (par[0] == 'E')
513     tty.sg_flags |= EVENP;
514   else if (par[0] == 'O')
515     tty.sg_flags |= ODDP;
516   else
517     tty.sg_flags |= PASS8 | ANYP;
518 
519   ioctl(fd, TIOCSETP, &tty);
520 
521 #  ifdef TIOCSDTR
522   /* FIXME: huh? - MvS */
523   ioctl(fd, TIOCSDTR, 0);
524 #  endif
525 #endif /* _BSD43 && !POSIX_TERMIOS */
526 
527 #if defined (_V7) && !defined(POSIX_TERMIOS)
528   if (spd != -1)
529     tty.sg_ispeed = tty.sg_ospeed = spd;
530   tty.sg_flags = RAW;
531   if (par[0] == 'E')
532     tty.sg_flags |= EVENP;
533   else if (par[0] == 'O')
534     tty.sg_flags |= ODDP;
535 
536   ioctl(fd, TIOCSETP, &tty);
537 #endif /* _V7 && !POSIX */
538 
539 #ifdef POSIX_TERMIOS
540 
541   if (spd != -1) {
542     cfsetospeed(&tty, (speed_t)spd);
543     cfsetispeed(&tty, (speed_t)spd);
544   }
545 
546   switch (bit) {
547     case '5':
548       tty.c_cflag = (tty.c_cflag & ~CSIZE) | CS5;
549       break;
550     case '6':
551       tty.c_cflag = (tty.c_cflag & ~CSIZE) | CS6;
552       break;
553     case '7':
554       tty.c_cflag = (tty.c_cflag & ~CSIZE) | CS7;
555       break;
556     case '8':
557     default:
558       tty.c_cflag = (tty.c_cflag & ~CSIZE) | CS8;
559       break;
560   }
561   /* Set into raw, no echo mode */
562   tty.c_iflag =  IGNBRK;
563   tty.c_lflag = 0;
564   tty.c_oflag = 0;
565   tty.c_cflag |= CLOCAL | CREAD;
566 #ifdef _DCDFLOW
567   tty.c_cflag &= ~CRTSCTS;
568 #endif
569   tty.c_cc[VMIN] = 1;
570   tty.c_cc[VTIME] = 5;
571 
572   if (swf)
573     tty.c_iflag |= IXON | IXOFF;
574   else
575     tty.c_iflag &= ~(IXON|IXOFF|IXANY);
576 
577   tty.c_cflag &= ~(PARENB | PARODD);
578   if (par[0] == 'E')
579     tty.c_cflag |= PARENB;
580   else if (par[0] == 'O')
581     tty.c_cflag |= (PARENB | PARODD);
582 
583   if (stopb[0] == '2')
584     tty.c_cflag |= CSTOPB;
585   else
586     tty.c_cflag &= ~CSTOPB;
587 
588   tcsetattr(fd, TCSANOW, &tty);
589 
590   m_setrts(fd);
591 #endif /* POSIX_TERMIOS */
592 
593 #ifndef _DCDFLOW
594   m_sethwf(fd, hwf);
595 #endif
596 }
597 
598 /*
599  * Wait for child and return pid + status
600  */
m_wait(int * stt)601 int m_wait(int *stt)
602 {
603 #if defined (_BSD43) && !defined(POSIX_TERMIOS)
604   int pid;
605   union wait st1;
606 
607   pid = wait((void *)&st1);
608   *stt = (unsigned)st1.w_retcode + 256 * (unsigned)st1.w_termsig;
609   return pid;
610 #else
611   int pid;
612   int st1;
613 
614   pid = wait(&st1);
615   *stt = (unsigned)WEXITSTATUS(st1) + 256 * (unsigned)WTERMSIG(st1);
616   return pid;
617 #endif
618 }
619