1 #ident "@(#)$Id: tio.c,v 4.9 2006/06/14 09:49:24 gert Exp $ Copyright (c) 1993 Gert Doering"
2 
3 /* tio.c
4  *
5  * contains routines dealing with SysV termio / POSIX termios / BSD sgtty
6  *
7  */
8 
9 #include <unistd.h>
10 #include <sys/types.h>
11 #include <errno.h>
12 
13 #ifdef NeXT
14 #include <sys/file.h>
15 #endif
16 
17 #include "mgetty.h"
18 #include "tio.h"
19 
20 #ifdef POSIX_TERMIOS
21 # ident "@(#)tio.c compiled with POSIX_TERMIOS"
22 #endif
23 #ifdef SYSV_TERMIO
24 # ident "@(#)tio.c compiled with SYSV_TERMIO"
25 #endif
26 #ifdef BSD_SGTTY
27 # ident "@(#)tio.c compiled with BSD_SGTTY"
28 #endif
29 
30 #ifdef USE_TERMIOX
31 # include <sys/termiox.h>
32 #endif
33 
34 #if defined( M_UNIX ) && defined( MAM_BUG )
35 #include <fcntl.h>
36 #endif
37 
38 #ifdef sysV68
39 #include <fcntl.h>
40 #include <errno.h>
41 #include <sys/tty.h>
42 #include <sys/sxt.h>
43 #include <sys/mvme332xt.h>
44 #endif
45 
46 /* some systems do not define all flags needed later, e.g. NetBSD */
47 
48 #if defined(BSD) || defined(__FreeBSD_kernel__)
49 # ifndef IUCLC
50 # define IUCLC 0
51 # endif
52 # ifndef TAB3
53 #  ifdef NeXT
54 #   define TAB3 XTABS
55 #  else
56 #   define TAB3 OXTABS
57 #  endif	/* !NeXT */
58 # endif
59 #endif
60 
61 /* baud rate table */
62 static struct	speedtab {
63 #ifdef POSIX_TERMIOS
64     speed_t	cbaud;
65 #else
66     unsigned short cbaud;	/* baud rate, e.g. B9600 */
67 #endif
68     int	 nspeed;		/* speed in numeric format */
69     char *speed;		/* speed in display format */
70 } speedtab[] = {
71 	{ B50,	  50,	 "50"	 },
72 	{ B75,	  75,	 "75"	 },
73 	{ B110,	  110,	 "110"	 },
74 	{ B134,	  134,	 "134"	 },
75 	{ B150,	  150,	 "150"	 },
76 	{ B200,	  200,	 "200"	 },
77 	{ B300,	  300,	 "300"	 },
78 	{ B600,	  600,	 "600"	 },
79 #ifdef	B900
80 	{ B900,	  900,	 "900"	},
81 #endif
82 	{ B1200,  1200,	 "1200"	 },
83 	{ B1800,  1800,	 "1800"	 },
84 	{ B2400,  2400,	 "2400"	 },
85 #ifdef	B3600
86 	{ B3600,  3600,	 "3600"	},
87 #endif
88 	{ B4800,  4800,	 "4800"	 },
89 #ifdef	B7200
90 	{ B7200,  7200,  "7200"	},
91 #endif
92 	{ B9600,  9600,	 "9600"	 },
93 #ifdef	B14400
94 	{ B14400, 14400, "14400" },
95 #endif
96 #ifdef	B19200
97 	{ B19200, 19200, "19200" },
98 #endif	/* B19200 */
99 #ifdef	B28800
100 	{ B28800, 28800, "28800" },
101 #endif
102 #ifdef	B38400
103 	{ B38400, 38400, "38400" },
104 #endif	/* B38400 */
105 #ifdef	EXTA
106 	{ EXTA,	  19200, "EXTA"	 },
107 #endif
108 #ifdef	EXTB
109 	{ EXTB,	  38400, "EXTB"	 },
110 #endif
111 #ifdef	B57600
112 	{ B57600, 57600, "57600" },
113 #endif
114 #ifdef	B76800
115 	{ B76800, 76800, "76800" },
116 #endif
117 #ifdef	B115200
118 	{ B115200,115200,"115200"},
119 #endif
120 #ifdef B230400
121 	{ B230400,230400,"230400"},
122 #endif
123 #ifdef B460800
124 	{ B460800,460800,"460800"},
125 #endif
126 	{ 0,	  0,	 ""	 }
127 };
128 
129 
130 /* get current tio settings for given filedescriptor */
131 
132 int tio_get _P2((fd, t), int fd, TIO *t )
133 {
134 #ifdef SYSV_TERMIO
135     if ( ioctl( fd, TCGETA, t ) < 0 )
136     {
137 	lprintf( L_ERROR, "TCGETA failed" ); return ERROR;
138     }
139 #endif
140 #ifdef POSIX_TERMIOS
141     if ( tcgetattr( fd, t ) < 0 )
142     {
143 	lprintf( L_ERROR, "tcgetattr failed" ); return ERROR;
144     }
145 #endif
146 #ifdef BSD_SGTTY
147     if ( gtty( fd, t ) < 0 )
148     {
149 	lprintf( L_ERROR, "gtty failed" ); return ERROR;
150     }
151 #endif
152     return NOERROR;
153 }
154 
155 int tio_set _P2( (fd, t), int fd, TIO * t)	/*!! FIXME: flags, wait */
156 {
157 #ifdef sunos4
158     int modem_lines;
159 #endif
160 #ifdef SYSV_TERMIO
161     if ( ioctl( fd, TCSETA, t ) < 0 )
162     {
163 	lprintf( L_ERROR, "ioctl TCSETA failed" ); return ERROR;
164     }
165 #endif
166 #ifdef POSIX_TERMIOS
167     if ( tcsetattr( fd, TCSANOW, t ) < 0 )
168     {
169 	lprintf( L_ERROR, "tcsetattr failed" ); return ERROR;
170     }
171 #ifdef sunos4
172     /* On SunOS, make sure that RTS and DTR are asserted if you wanna
173      * use hardware flow control
174      */
175     if (t->c_cflag & CRTSCTS)
176     {
177         /* make sure RTS is asserted!!!!!! */
178         ioctl(fd, TIOCMGET, &modem_lines);
179         modem_lines |= (TIOCM_RTS | TIOCM_DTR);
180         ioctl(fd, TIOCMSET, &modem_lines);
181     }
182 #endif /* sunos4 */
183 #endif /* posix_termios */
184 
185 #ifdef BSD_SGTTY
186     if ( stty( fd, t ) < 0 )
187     {
188 	lprintf( L_ERROR, "stty failed" ); return ERROR;
189     }
190 #endif
191     return NOERROR;
192 }
193 
194 /* check whether a given speed (integer) is valid for the given system */
195 int tio_check_speed _P1( (speed), int speed )
196 {
197     int i;
198     for ( i=0; speedtab[i].cbaud != 0; i++ )
199     {
200 	if ( speedtab[i].nspeed == speed )
201 	{
202 	    return speedtab[i].cbaud;
203 	}
204     }
205     lprintf( L_NOISE, "speed %d not found in table", speed );
206     errno=EINVAL;
207     return -1;
208 }
209 
210 /* set speed, do not touch the other flags
211  * "speed" is given as numeric baud rate, not as Bxxx constant
212  */
213 int tio_set_speed _P2( (t, speed ), TIO *t, unsigned int speed )
214 {
215     int i, symspeed=0;
216 
217     for ( i=0; speedtab[i].cbaud != 0; i++ )
218     {
219 	if ( speedtab[i].nspeed == speed )
220 		{ symspeed = speedtab[i].cbaud; break; }
221     }
222 
223     if ( symspeed == 0 )
224     {
225 	errno=EINVAL;
226 	lprintf( L_ERROR, "tss: unknown/unsupported bit rate: %d", speed );
227 	return ERROR;
228     }
229 
230     lprintf( L_NOISE, "tss: set speed to %d (%03o)", speed, symspeed );
231 
232 #ifdef SYSV_TERMIO
233     t->c_cflag = ( t->c_cflag & ~CBAUD) | symspeed;
234 #endif
235 #ifdef POSIX_TERMIOS
236     cfsetospeed( t, symspeed );
237     cfsetispeed( t, symspeed );
238 #endif
239 #ifdef BSD_SGTTY
240     t->sg_ispeed = t->sg_ospeed = symspeed;
241 #endif
242     return NOERROR;
243 }
244 
245 /* get port speed. Return integer value, not symbolic constant */
246 int tio_get_speed _P1( (t), TIO *t )
247 {
248 #ifdef SYSV_TERMIO
249     ushort cbaud = t->c_cflag & CBAUD;
250 #endif
251 #ifdef POSIX_TERMIOS
252     speed_t cbaud = cfgetospeed( t );
253 #endif
254 #ifdef BSD_SGTTY
255     int cbaud = t->sg_ospeed;
256 #endif
257     struct speedtab * p;
258 
259     for ( p=speedtab; p->nspeed != 0; p++ )
260     {
261 	if ( p->cbaud == cbaud ) break;
262     }
263     return p->nspeed;
264 }
265 
266 
267 /* set "raw" mode: do not process input or output, do not buffer */
268 /* do not touch cflags or xon/xoff flow control flags */
269 
270 void tio_mode_raw _P1( (t), TIO * t )
271 {
272 #if defined(SYSV_TERMIO) || defined( POSIX_TERMIOS)
273     t->c_iflag &= ( IXON | IXOFF | IXANY );	/* clear all flags except */
274 						/* xon / xoff handshake */
275     t->c_oflag  = 0;				/* no output processing */
276     t->c_lflag  = 0;				/* no signals, no echo */
277 
278     t->c_cc[VMIN]  = 1;				/* disable line buffering */
279     t->c_cc[VTIME] = 0;
280 #else
281     t->sg_flags = RAW;
282 #endif
283 }
284 
285 /* "cbreak" mode - do not process input in lines, but process ctrl
286  * characters, echo characters back, ...
287  * warning: must be based on raw / sane mode
288  */
289 void tio_mode_cbreak _P1( (t), TIO * t )
290 {
291 #if defined(SYSV_TERMIO) || defined(POSIX_TERMIOS)
292     t->c_oflag = 0;
293     t->c_iflag &= ~( IGNCR | ICRNL | INLCR | IUCLC );
294     t->c_lflag &= ~( ICANON | ISIG );
295     t->c_cc[VMIN] = 1;
296     t->c_cc[VTIME]= 0;
297 #else
298     t->sg_flags |= CBREAK;
299 #endif
300 }
301 
302 /* set "sane" mode, usable for login, ...
303  * unlike the other tio_mode_* functions, this function initializes
304  * all flags, and should be called before calling any other function
305  */
306 void tio_mode_sane _P2( (t, local), TIO * t, int local )
307 {
308 #if defined(SYSV_TERMIO) || defined( POSIX_TERMIOS )
309     t->c_iflag = BRKINT | IGNPAR | IXON | IXANY;
310     t->c_oflag = OPOST | TAB3;
311     /* be careful, only touch "known" flags */
312     t->c_cflag&= ~(CSIZE | CSTOPB | PARENB | PARODD | CLOCAL);
313     t->c_cflag|= CS8 | CREAD | HUPCL | ( local? CLOCAL:0 );
314     t->c_lflag = ECHOK | ECHOE | ECHO | ISIG | ICANON;
315 
316 #if !defined(POSIX_TERMIOS)
317     t->c_line  = 0;
318 #endif
319 
320     /* initialize the most important c_cc's here */
321     t->c_cc[VEOF] = 0x04;
322 #if defined(VEOL) && VEOL < TIONCC
323     t->c_cc[VEOL] = 0;
324 #endif
325 
326 #ifdef VSWTCH
327     t->c_cc[VSWTCH] = 0;
328 #endif
329 
330 #else		/* BSD_SGTTY */
331     t->sg_flags = ECHO | EVENP | ODDP;
332 /*    t->sg_flags = ECHO; */
333     t->sg_erase = 0x7f;            /* erase character */
334     t->sg_kill  = 0x25;            /* kill character, ^u */
335 #endif
336 }
337 
338 /* tio_default_cc( TIO )
339  *
340  * initialize all c_cc fields (for POSIX and SYSV) to proper start
341  * values (normally, the serial driver should do this, but there are
342  * numerous systems where some of the more esoteric (VDSUSP...) flags
343  * are plain wrong (e.g. set to "m" or so)
344  *
345  * do /not/ initialize VERASE and VINTR, since some systems use
346  * ^H / DEL here, others DEL / ^C.
347  */
348 void tio_default_cc _P1( (t), TIO *t )
349 {
350 #ifdef BSD_SGTTY
351     t->sg_erase = 0x7f;            /* erase character */
352     t->sg_kill  = 0x25;            /* kill character, ^u */
353 
354 #else /* posix or sysv */
355     t->c_cc[VQUIT]  = CQUIT;
356     t->c_cc[VKILL]  = CKILL;
357     t->c_cc[VEOF]   = CEOF;
358 #if defined(VEOL) && VEOL < TIONCC
359     t->c_cc[VEOL] = CEOL;
360 #endif
361 #if defined(VSTART) && VSTART < TIONCC
362     t->c_cc[VSTART] = CSTART;
363 #endif
364 #if defined(VSTOP) && VSTOP < TIONCC
365     t->c_cc[VSTOP] = CSTOP;
366 #endif
367 #if defined(VSUSP) && VSUSP < TIONCC
368     t->c_cc[VSUSP] = CSUSP;
369 #endif
370 #if defined(VSWTCH) && VSWTCH < TIONCC
371     t->c_cc[VSWTCH] = CSWTCH;
372 #endif
373     /* the following are for SVR4.2 (and higher) */
374 #if defined(VDSUSP) && VDSUSP < TIONCC
375     t->c_cc[VDSUSP] = CDSUSP;
376 #endif
377 #if defined(VREPRINT) && VREPRINT < TIONCC
378     t->c_cc[VREPRINT] = CRPRNT;
379 #endif
380 #if defined(VDISCARD) && VDISCARD < TIONCC
381     t->c_cc[VDISCARD] = CFLUSH;
382 #endif
383 #if defined(VWERASE) && VWERASE < TIONCC
384     t->c_cc[VWERASE] = CWERASE;
385 #endif
386 #if defined(VLNEXT) && VLNEXT < TIONCC
387     t->c_cc[VLNEXT] = CLNEXT;
388 #endif
389 
390 #endif /* bsd <-> posix + sysv */
391 }
392 
393 
394 void tio_map_cr _P2( (t, perform_mapping), TIO * t, int
395 		    perform_mapping )
396 {
397 #if defined(SYSV_TERMIO) || defined(POSIX_TERMIOS)
398     if ( perform_mapping )
399     {
400 	t->c_iflag |= ICRNL;
401 	t->c_oflag |= ONLCR;
402     }
403     else
404     {
405 	t->c_iflag &= ~ICRNL;
406 	t->c_oflag &= ~ONLCR;
407     }
408 #else		/* BSD_SGTTY (tested only on NeXT yet, but should work) */
409     if ( perform_mapping )
410     {
411         t->sg_flags |= CRMOD ;
412     }
413     else
414     {
415         t->sg_flags &= ~CRMOD ;
416     }
417 #endif
418 }
419 
420 /* enable uppercase <-> lowercase mapping */
421 
422 void tio_map_uclc _P2( (t, perform_mapping), TIO * t, int
423 		    perform_mapping )
424 {
425 #if defined(__bsdi__) || !defined(OLCUC) || !defined(XCASE)
426     lprintf( L_WARN, "uclc mapping not available" );
427 #else
428 # if defined(SYSV_TERMIO) || defined(POSIX_TERMIOS)
429     if ( perform_mapping )
430     {
431 	t->c_iflag |= IUCLC;
432 	t->c_oflag |= OLCUC;
433 	t->c_lflag |= XCASE;
434     }
435     else
436     {
437 	t->c_iflag &= ~IUCLC;
438 	t->c_oflag &= ~OLCUC;
439 	t->c_lflag &= ~XCASE;
440     }
441 # else		/* BSD_SGTTY */
442 #  include "not implemented yet"
443 # endif
444 #endif		/* BSDI */
445 }
446 
447 /* tio_carrier()
448  * specify whether the port should be carrier-sensitive or not
449  */
450 
451 void tio_carrier _P2( (t, carrier_sensitive), TIO *t, int carrier_sensitive )
452 {
453 #if defined(SYSV_TERMIO) || defined(POSIX_TERMIOS)
454     if ( carrier_sensitive )
455     {
456 	t->c_cflag &= ~CLOCAL;
457     }
458     else
459     {
460 	t->c_cflag |= CLOCAL;
461     }
462 #else		/* BSD_SGTTY (tested only on NeXT yet, but should work) */
463     if ( carrier_sensitive )
464     {
465         t->sg_flags &= ~LNOHANG ;
466     }
467     else
468     {
469         t->sg_flags |= LNOHANG ;
470     }
471 #endif
472 }
473 
474 /* set handshake */
475 
476 /* hardware handshake flags - use what is available on local system
477  */
478 
479 #ifdef CRTSCTS
480 # define HARDWARE_HANDSHAKE CRTSCTS		/* linux, SunOS */
481 #else
482 # ifdef CRTSFL
483 #  define HARDWARE_HANDSHAKE CRTSFL		/* SCO 3.2v4.2 */
484 # else
485 #  ifdef RTSFLOW
486 #   define HARDWARE_HANDSHAKE RTSFLOW | CTSFLOW	/* SCO 3.2v2 */
487 #  else
488 #   ifdef CTSCD
489 #    define HARDWARE_HANDSHAKE CTSCD		/* AT&T 3b1? */
490 #   else
491 #    define HARDWARE_HANDSHAKE 0		/* nothing there... */
492 #   endif
493 #  endif
494 # endif
495 #endif
496 
497 /* Dial-Out parallel to a Dial-in on SCO 3.2v4.0 does only work if
498  * *only* CTSFLOW is set (Uwe S. Fuerst)
499  */
500 #ifdef BROKEN_SCO_324
501 # undef HARDWARE_HANDSHAKE
502 # define HARDWARE_HANDSHAKE CTSFLOW
503 #endif
504 
505 /* tio_set_flow_control
506  *
507  * set flow control according to the <type> parameter. It can be any
508  * combination of
509  *   FLOW_XON_IN - use Xon/Xoff on incoming data
510  *   FLOW_XON_OUT- respect Xon/Xoff on outgoing data
511  *   FLOW_HARD   - use RTS/respect CTS line for hardware handshake
512  * (not every combination will work on every system)
513  *
514  * WARNING: for most systems, this function will not touch the tty
515  *          settings, only modify the TIO structure. On some systems,
516  *          you have to use extra ioctl()s [notably SVR4, sysV68, and
517  *          AIX] to modify hardware flow control settings. On those
518  *          systems, these calls are done immediately.
519  */
520 
521 int tio_set_flow_control _P3( (fd, t, type), int fd, TIO * t, int type )
522 {
523 #ifdef USE_TERMIOX
524     struct termiox tix;
525 #endif
526 
527     lprintf( L_NOISE, "tio_set_flow_control(%s%s%s )",
528 		      type & FLOW_HARD   ? " HARD": "",
529 		      type & FLOW_XON_IN ? " XON_IN": "",
530 		      type & FLOW_XON_OUT? " XON_OUT": "" );
531 
532 #if defined( SYSV_TERMIO ) || defined( POSIX_TERMIOS )
533     t->c_cflag &= ~HARDWARE_HANDSHAKE;
534     t->c_iflag &= ~( IXON | IXOFF | IXANY );
535 
536     if ( type & FLOW_HARD )
537 			t->c_cflag |= HARDWARE_HANDSHAKE;
538     if ( type & FLOW_XON_IN )
539 			t->c_iflag |= IXOFF;
540     /* for login, we want IXON|IXANY, for voice, we must not set IXANY! */
541     if ( type & FLOW_XON_OUT )
542     {
543 	                t->c_iflag |= IXON;
544         if ( type & FLOW_XON_IXANY )
545 	                t->c_iflag |= IXANY;
546     }
547 #else
548 # ifdef NEXTSGTTY
549     lprintf( L_WARN, "tio_set_flow_control: not yet implemented" );
550 # else
551 #  include "not yet implemented"
552 # endif
553 #endif
554 
555     /* SVR4 came up with a new method of setting h/w flow control */
556 #ifdef USE_TERMIOX
557     lprintf( L_NOISE, "tio_set_flow_control: using termiox" );
558 
559     if (ioctl(fd, TCGETX, &tix) < 0)
560     {
561 	lprintf( L_ERROR, "ioctl TCGETX" ); return ERROR;
562     }
563     if ( type & FLOW_HARD )
564         tix.x_hflag |= (RTSXOFF | CTSXON);
565     else
566         tix.x_hflag &= ~(RTSXOFF | CTSXON);
567 
568     if ( ioctl(fd, TCSETX, &tix) < 0 )
569     {
570 	lprintf( L_ERROR, "ioctl TCSETX" ); return ERROR;
571     }
572 #endif
573     /* AIX has yet another method to set hardware flow control
574      * interesting enough, in AIX 4, this ioctl still exists but doesn't
575      * work anymore -- instead, they have adopted termiox. *bah*
576      */
577 #if defined(_AIX) && !defined(USE_TERMIOX)
578     lprintf( L_NOISE, "tio_set_flow_control: using TXADDCD" );
579 
580     if ( ioctl( fd, ( type & FLOW_HARD ) ? TXADDCD : TXDELCD, "rts" ) < 0 )
581     {
582 	lprintf( L_NOISE, "ioctl TXADDCD/TXDELCD failed, errno=%d", errno);
583 	return ERROR;
584     }
585 #ifdef DEBUG
586     {	union txname t; int i;
587 	lprintf( L_NOISE, "control disciplines:");
588 	for ( i=1; ; i++ ) {
589 	    t.tx_which = i;
590 	    if ( ioctl( fd, TXGETCD, &t ) ) {
591 		lprintf( L_FATAL, "TXGETCD error" ); break;
592 	    }
593 	    if ( t.tx_name == NULL || !t.tx_name[0] ) break;
594 	    lputc( L_NOISE, ' ');
595 	    lputs( L_NOISE, t.tx_name );
596 	}
597     }
598 #endif			/* DEBUG */
599 #endif			/* _AIX */
600 
601 /*
602  * sysV68 uses special ioctls, too. The following code should work for
603  * mvme332xt controllers. The mvme337 driver supports the same ioctls
604  * but has not been tested. Others may not support hardware flow
605  * control at all. Refer to the corresponding mvmeXXX(7) manpage for
606  * details.
607  */
608 #ifdef sysV68
609     lprintf( L_NOISE, "tio_set_flow_control: using TCSETHW" );
610 
611     if ( type & FLOW_HARD ) {
612 	if ( ioctl(fd, TCSETHW, 1) < 0 ) {
613 		lprintf( L_ERROR, "ioctl TCSETHW on failed" );
614 		return ERROR;
615 	}
616     } else {
617 	if ( ioctl(fd, TCSETHW, 0) < 0 ) {
618 		/* We use a lower logging priority if errno is EINVAL, so
619 		 * mgetty can be used on devices which do not support the
620 		 * special m332xt ioctls without filling syslog with
621 		 * unnecessary error messages.
622 		 */
623 		if (EINVAL == errno) {
624 			lprintf( L_NOISE, "ioctl TCSETHW off failed" );
625 		} else {
626 			lprintf( L_ERROR, "ioctl TCSETHW off failed" );
627 			return ERROR;
628 		}
629 	}
630     }
631 #endif /* sysV68 */
632     return NOERROR;
633 }
634 
635 /* for convenience - do not have to get termio settings before, but
636  * it's slower (two system calls more)
637  */
638 int tio_set_flow_control2 _P2( (fd, type), int fd, int type )
639 {
640 TIO t;
641 
642     if ( tio_get( fd, &t ) == ERROR ) return ERROR;
643 
644     tio_set_flow_control( fd, &t, type );
645 
646     return tio_set( fd, &t );
647 }
648 
649 int tio_toggle_dtr _P2( (fd, msec_wait), int fd, int msec_wait )
650 {
651     /* On SVR4.2, lowering DTR by setting the port speed to zero will
652      * bring the port to some strange state where every ioctl() later
653      * on simply fails - so use special "modem control" ioctl()s to
654      * lower and raise DTR
655      * Strange enough, on *some* platforms, you have to pass the mctl
656      * flag word by value, on others by reference. Oh world...
657      */
658 #if defined(TIOCMBIS) && \
659     ( defined(sun) || defined(SVR4) || defined(NeXT) || defined(linux) )
660 
661     int mctl = TIOCM_DTR;
662 
663 #if !defined( TIOCM_VALUE )
664     if ( ioctl( fd, TIOCMBIC, &mctl ) < 0 )
665 #else
666     if ( ioctl( fd, TIOCMBIC, (char *) mctl ) < 0 )
667 #endif
668     {
669 	lprintf( L_ERROR, "TIOCMBIC failed" ); return ERROR;
670     }
671     delay( msec_wait );
672 #if !defined( TIOCM_VALUE)
673     if ( ioctl( fd, TIOCMBIS, &mctl ) < 0 )
674 #else
675     if ( ioctl( fd, TIOCMBIS, (char *) mctl ) < 0 )
676 #endif
677     {
678 	lprintf( L_ERROR, "TIOCMBIS failed" ); return ERROR;
679     }
680     return NOERROR;
681 #else						/* !TIOCMBI* */
682 
683     /* On HP/UX, lowering DTR by setting the port speed to B0 will
684      * leave it there. So, do it via HP/UX's special ioctl()'s...
685      */
686 #if defined(_HPUX_SOURCE) || defined(MCGETA)
687     unsigned long mflag = 0L;
688 
689     if ( ioctl( fd, MCSETAF, &mflag ) < 0 )
690     {
691 	lprintf( L_ERROR, "MCSETAF failed" ); return ERROR;
692     }
693     delay( msec_wait );
694     if ( ioctl( fd, MCGETA, &mflag ) < 0 )
695     {
696 	lprintf( L_ERROR, "MCGETA failed" ); return ERROR;
697     }
698     mflag = MRTS | MDTR;
699     if ( ioctl( fd, MCSETAF, &mflag ) < 0 )
700     {
701 	lprintf( L_ERROR, "MCSETAF failed" ); return ERROR;
702     }
703     return NOERROR;
704 
705 #else /* !MCGETA */
706 
707     /* The "standard" way of doing things - via speed = B0
708      */
709     TIO t, save_t;
710 #ifdef sunos4
711     int modem_lines;
712 #endif
713     int result;
714 
715     if ( tio_get( fd, &t ) == ERROR ) return ERROR;
716 
717     save_t = t;
718 
719 #ifdef SYSV_TERMIO
720     t.c_cflag = ( t.c_cflag & ~CBAUD ) | B0;		/* speed = 0 */
721 #endif
722 #ifdef POSIX_TERMIOS
723     cfsetospeed( &t, B0 );
724     cfsetispeed( &t, B0 );
725 #endif
726 #ifdef BSD_SGTTY
727     t.sg_ispeed = t.sg_ospeed = B0
728 #endif
729 
730     tio_set( fd, &t );
731     delay( msec_wait );
732 
733 #ifdef sunos4
734     /* on SunOS, if you hangup via B0, the DTR line will *stay* low.
735      * So: enable it manually again.
736      */
737     ioctl(fd, TIOCMGET, &modem_lines);
738     modem_lines |= (TIOCM_RTS | TIOCM_DTR);
739     ioctl(fd, TIOCMSET, &modem_lines);
740 #endif
741     result = tio_set( fd, &save_t );
742 
743 #if (defined(M_UNIX) && defined(MAM_BUG)) || defined (sysV68)
744     /* some Unix variants apparently forget to raise DTR again
745      * after lowering it. Reopening the port fixes it. Crude, but works.
746      */
747     close( open( "/dev/tty", O_RDONLY | O_NDELAY ) );
748 #endif
749 
750     return result;
751 #endif					/* !MCSETA */
752 #endif					/* !SVR4 */
753 }
754 
755 
756 /* flush input or output data queue
757  *
758  * "queue" is one of the TIO_Q* values from tio.h
759  */
760 
761 int tio_flush_queue _P2( (fd, queue), int fd, int queue )
762 {
763     int r = NOERROR;
764 #ifdef POSIX_TERMIOS
765     switch( queue )
766     {
767       case TIO_Q_IN:   r = tcflush( fd, TCIFLUSH ); break;
768       case TIO_Q_OUT:  r = tcflush( fd, TCOFLUSH ); break;
769       case TIO_Q_BOTH: r = tcflush( fd, TCIOFLUSH );break;
770       default:
771 	lprintf( L_WARN, "tio_flush_queue: invalid ``queue'' argument" );
772 	return ERROR;
773     }
774 #endif
775 #ifdef SYSV_TERMIO
776     switch ( queue )
777     {
778       case TIO_Q_IN:   r = ioctl( fd, TCFLSH, 0 ); break;
779       case TIO_Q_OUT:  r = ioctl( fd, TCFLSH, 1 ); break;
780       case TIO_Q_BOTH: r = ioctl( fd, TCFLSH, 2 ); break;
781       default:
782 	lprintf( L_WARN, "tio_flush_queue: invalid ``queue'' argument" );
783 	return ERROR;
784     }
785 #endif
786 #ifdef BSD_SGTTY
787     int arg;
788 
789     switch ( queue )
790     {
791       case TIO_Q_IN:   arg = FREAD; break;
792       case TIO_Q_OUT:  arg = FWRITE; break;
793       case TIO_Q_BOTH: arg = FREAD | FWRITE; break;
794       default:
795 	lprintf( L_WARN, "tio_flush_queue: invalid ``queue'' argument" );
796 	return ERROR;
797     }
798     r = ioctl( fd, TIOCFLUSH, (char *) &arg );
799 #endif
800     if ( r != 0 ) lprintf( L_ERROR, "tio: cannot flush queue" );
801 
802     return r;
803 }
804 
805 /* control flow control: if "restart_output" is TRUE, stopped tty output is
806  * resumed, if it is FALSE, the output is stopped
807  *
808  * I'm fairly sure it won't work on all supported systems...
809  */
810 
811 int tio_flow _P2( (fd, restart_output), int fd, int restart_output )
812 {
813     int r;
814 #ifdef POSIX_TERMIOS
815     if ( restart_output ) r = tcflow( fd, TCOON );
816                      else r = tcflow( fd, TCOOFF );
817 #endif
818 #ifdef SYSV_TERMIO
819     if ( restart_output ) r = ioctl( fd, TCXONC, 1 );
820                      else r = ioctl( fd, TCXONC, 0 );
821 #endif
822 #ifdef BSD_SGTTY
823     if ( restart_output ) r = ioctl( fd, TIOCSTART, NULL );
824                      else r = ioctl( fd, TIOCSTOP, NULL );
825 #endif
826     if ( r != 0 ) lprintf( L_ERROR, "tio: cannot change flow ctrl state" );
827 
828     return r;
829 }
830 
831 
832 /* tio_drain(fd): wait for output queue to drain
833  */
834 
835 int tio_drain_output _P1( (fd), int fd )
836 {
837 #ifdef POSIX_TERMIOS
838     if ( tcdrain( fd ) == ERROR )
839     {
840 	lprintf( L_ERROR, "tio_drain: tcdrain" ); return ERROR;
841     }
842 #else
843 # ifdef SYSV_TERMIO
844     if ( ioctl( fd, TCSBRK, 1 ) == ERROR )
845     {
846     	lprintf( L_ERROR, "tio_drain: TCSBRK/1" ); return ERROR;
847     }
848 # else	/* no way to wait for data to drain with BSD_SGTTY */
849     lprintf( L_WARN, "tio_drain: expect spurious failures" );
850 # endif
851 #endif
852     return NOERROR;
853 }
854 
855 /* send a BREAK signal to the tty
856  *
857  * kernel break via tcsendbreak() or ioctl(TCSENDBRK) lasts at least
858  * 0.25 seconds. We can speed up this by switching baud rate to 1/4,
859  * and then sending a 0-byte (activated #ifdef FAST_BREAK).
860  *
861  * on some systems (don't we love it all?) the "real" break functions
862  * don't work, so we must use FAST_BREAK.
863  */
864 
865 int tio_break _P1((fd), int fd)
866 {
867 /* SunOS4 doesn't seem to like "tcsendbreak" (noop), so send a "long zero" */
868 #if defined(sunos4) || defined(M_UNIX) || defined(FAST_BREAK)
869     TIO tio, tio_save; int speed; char null = 0;
870 
871     lprintf( L_NOISE, "sending FAST break" );
872 
873     if ( tio_get( fd, &tio ) == ERROR )
874     {
875 	lprintf( L_ERROR, "tio_break: can't get tio" ); return ERROR;
876     }
877     tio_save = tio;
878     if ( (speed = tio_get_speed( &tio ) ) < 150 ||
879 	 tio_set_speed( &tio, speed/4 ) == ERROR ||
880 	 tio_set( fd, &tio ) == ERROR )
881     {
882 	lprintf( L_ERROR, "tio_break: can't set 1/4 speed" ); return ERROR;
883     }
884     if ( write( fd, &null, 1 ) != 1 )
885     {
886 	lprintf( L_ERROR, "tio_break: can't write 0-byte" ); return ERROR;
887     }
888 
889     /* before we switch baud rates back, make sure zero byte has been sent!
890      */
891     if ( tio_drain_output( fd ) == ERROR ) return ERROR;
892 
893     if ( tio_set( fd, &tio_save ) == ERROR )
894     {
895 	lprintf( L_ERROR, "tio_break: can't reset old TIO state" ); return ERROR;
896     }
897 
898 #else	/* !FAST_BREAK -> use standard functions */
899 
900     lprintf( L_NOISE, "sending system call break" );
901 #ifdef POSIX_TERMIOS
902     if ( tcsendbreak( fd, 0 ) < 0 )
903     {
904     	lprintf( L_ERROR, "tcsendbreak() failed" );
905     	return ERROR;
906     }
907 #endif
908 #ifdef SYSV_TERMIO
909     if ( ioctl( fd, TCSBRK, 0 ) < 0 )
910     {
911     	lprintf( L_ERROR, "ioctl( TCSBRK ) failed" );
912     	return ERROR;
913     }
914 #endif
915 #ifdef BSD_SGTTY
916    if ( ioctl( fd, TIOCSBRK, 0 ) < 0 )
917    {
918    	lprintf( L_ERROR, "ioctl( TIOCSBRK ) failed" );
919    	return ERROR;
920    }
921    delay( 250 );
922    if ( ioctl( fd, TIOCCBRK, 0 ) < 0 )
923    {
924    	lprintf( L_ERROR, "ioctl( TIOCCBRK ) failed" );
925    	return ERROR;
926    }
927 #endif
928 #endif /* FAST_BREAK */
929    return NOERROR;
930 }
931 
932 /* tio_get_rs232_lines()
933  *
934  * get the status of all RS232 status lines
935  * (coded by the TIO_F_* flags. On systems that have the BSD TIOCM_*
936  * flags, we use them, on others we may have to do some other tricks)
937  *
938  * "-1" can mean "error" or "not supported on this system" (e.g. SCO).
939  */
940 
941 int tio_get_rs232_lines _P1( (fd), int fd)
942 {
943     int flags;
944 #ifdef TIO_F_SYSTEM_DEFS
945     if ( ioctl(fd, TIOCMGET, &flags ) < 0 )
946     	lprintf( L_ERROR, "tio_get_rs232_lines: TIOCMGET failed" );
947 
948 #else /* !TIO_F_SYSTEM_DEFS */
949     flags=-1;
950 #endif
951 
952     if ( flags != -1 )
953     {
954         lprintf( L_NOISE, "tio_get_rs232_lines: status:" );
955         if ( flags & TIO_F_RTS ) lputs( L_NOISE, " RTS" );
956         if ( flags & TIO_F_CTS ) lputs( L_NOISE, " CTS" );
957         if ( flags & TIO_F_DSR ) lputs( L_NOISE, " DSR" );
958         if ( flags & TIO_F_DTR ) lputs( L_NOISE, " DTR" );
959         if ( flags & TIO_F_DCD ) lputs( L_NOISE, " DCD" );
960         if ( flags & TIO_F_RI  ) lputs( L_NOISE, " RI" );
961     }
962     return flags;
963 }
964 
965 /* tio_set_rs232_lines()
966  *
967  * set the status of the DTR and RTS RS232 status lines
968  * (coded by the TIO_F_* flags. On systems that have the BSD TIOCM_*
969  * flags, we use them, on others we may have to do some other tricks)
970  *
971  * "-1" can mean "error" or "not supported on this system" (e.g. SCO).
972  */
973 
974 int tio_set_rs232_lines _P3( (fd, do_dtr, do_rts),
975 				int fd, int do_dtr, int do_rts )
976 {
977     int mctl, rc=0;
978 
979 #ifdef TIO_F_SYSTEM_DEFS
980     mctl = TIOCM_DTR;
981     if ( do_dtr != -1 &&
982          ioctl( fd, do_dtr? TIOCMBIS: TIOCMBIC, &mctl ) < 0 )
983     {
984 	lprintf( L_ERROR, "tio_set_rs232_lines: %s DTR failed",
985 			do_dtr? "set": "clear" );
986 	rc=-1;
987     }
988 
989     mctl = TIOCM_RTS;
990     if ( do_rts != -1 &&
991          ioctl( fd, do_rts? TIOCMBIS: TIOCMBIC, &mctl ) < 0 )
992     {
993 	lprintf( L_ERROR, "tio_set_rs232_lines: %s RTS failed",
994 			do_rts? "set": "clear" );
995 	rc=-1;
996     }
997 
998 #else
999     lprintf( L_WARN, "setting of RS232 lines not supported" );
1000 #endif
1001     return rc;
1002 }
1003