xref: /illumos-gate/usr/src/cmd/bnu/line.c (revision dd72704bd9e794056c558153663c739e2012d721)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 
22 /*
23  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
28 /*	  All Rights Reserved  	*/
29 
30 /*
31  * This is a new line.c, which consists of line.c and culine.c
32  * merged together.
33  */
34 
35 #include "uucp.h"
36 
37 static struct sg_spds {
38 	int sp_val;
39 	int sp_name;
40 } spds[] = {
41 	{ 50,		B50 },
42 	{ 75,		B75 },
43 	{ 110,		B110 },
44 	{ 134,		B134 },
45 	{ 150,		B150 },
46 	{ 200,		B200 },
47 	{ 300,		B300 },
48 	{ 600,		B600 },
49 	{ 1200,		B1200 },
50 	{ 1800,		B1800 },
51 	{ 2400,		B2400 },
52 	{ 4800,		B4800 },
53 	{ 9600,		B9600 },
54 	{ 19200,	B19200 },
55 	{ 38400,	B38400 },
56 	{ 57600,	B57600 },
57 	{ 76800,	B76800 },
58 	{ 115200,	B115200 },
59 	{ 153600,	B153600 },
60 	{ 230400,	B230400 },
61 	{ 307200,	B307200 },
62 	{ 460800,	B460800 },
63 	{ 921600,	B921600 },
64 	{ 1000000,	B1000000 },
65 	{ 1152000,	B1152000 },
66 	{ 1500000,	B1500000 },
67 	{ 2000000,	B2000000 },
68 	{ 2500000,	B2500000 },
69 	{ 3000000,	B3000000 },
70 	{ 3500000,	B3500000 },
71 	{ 4000000,	B4000000 },
72 	{ 0,		0}
73 };
74 
75 #define	PACKSIZE	64
76 #define	HEADERSIZE	6
77 
78 GLOBAL int
79 	packsize = PACKSIZE,
80 	xpacksize = PACKSIZE;
81 
82 #define	SNDFILE	'S'
83 #define	RCVFILE 'R'
84 #define	RESET	'X'
85 
86 #ifdef PKSPEEDUP
87 GLOBAL int linebaudrate;	/* for speedup hook in pk1.c */
88 #endif /*  PKSPEEDUP  */
89 static int Saved_line;		/* was savline() successful?	*/
90 static int Saved_termios;	/* was termios saved?	*/
91 GLOBAL int
92 	Oddflag = 0,	/* Default is no parity */
93 	Evenflag = 0,	/* Default is no parity */
94 	Duplex = 1,	/* Default is full duplex */
95 	Terminal = 0,	/* Default is no terminal */
96 	term_8bit = -1,	/* Default to terminal setting or 8 bit */
97 	line_8bit = -1;	/* Default is same as terminal */
98 
99 static char *P_PARITY  = "Parity option error\r\n";
100 
101 #ifdef ATTSVTTY
102 
103 static struct termio Savettyb;
104 static struct termios Savettybs;
105 /*
106  * set speed/echo/mode...
107  *	tty 	-> terminal name
108  *	spwant 	-> speed
109  *	type	-> type
110  *
111  *	if spwant == 0, speed is untouched
112  *	type is unused, but needed for compatibility
113  *
114  * return:
115  *	none
116  */
117 /*ARGSUSED*/
118 GLOBAL void
119 fixline(tty, spwant, type)
120 int	tty, spwant, type;
121 {
122 	register struct sg_spds	*ps;
123 	struct termio		ttbuf;
124 	struct termios		ttbufs;
125 	int			speed = -1;
126 	int			i, istermios, ospeed;
127 
128 	DEBUG(6, "fixline(%d, ", tty);
129 	DEBUG(6, "%d)\n", spwant);
130 	if ((istermios = (*Ioctl)(tty, TCGETS, &ttbufs)) < 0) {
131 		if ((*Ioctl)(tty, TCGETA, &ttbuf) != 0) {
132 			return;
133 		} else {
134 			ttbufs.c_lflag = ttbuf.c_lflag;
135 			ttbufs.c_oflag = ttbuf.c_oflag;
136 			ttbufs.c_iflag = ttbuf.c_iflag;
137 			ttbufs.c_cflag = ttbuf.c_cflag;
138 			for (i = 0; i < NCC; i++)
139 				ttbufs.c_cc[i] = ttbuf.c_cc[i];
140 		}
141 	}
142 	if (spwant > 0) {
143 		for (ps = spds; ps->sp_val; ps++)
144 			if (ps->sp_val == spwant) {
145 				speed = ps->sp_name;
146 				break;
147 			}
148 		if (speed < 0)
149 			DEBUG(5, "speed (%d) not supported\n", spwant);
150 		ASSERT(speed >= 0, "BAD SPEED", "", spwant);
151 		ttbufs.c_cflag &= 0xffff0000;
152 		cfsetospeed(&ttbufs, speed);
153 	} else { /* determine the current speed setting */
154 		ospeed = cfgetospeed(&ttbufs);
155 		ttbufs.c_cflag &= 0xffff0000;
156 		cfsetospeed(&ttbufs, ospeed);
157 		for (ps = spds; ps->sp_val; ps++)
158 			if (ps->sp_name == ospeed) {
159 				spwant = ps->sp_val;
160 				break;
161 			}
162 	}
163 	/*
164 	 * In order to prevent attempts at split speed, all baud rate
165 	 * bitfields should be cleared. Thus cfsetispeed is used to
166 	 * set the speed to zero.
167 	 */
168 	(void) cfsetispeed(&ttbufs, 0);
169 	ttbufs.c_iflag &= 0xffff0000;
170 	ttbufs.c_oflag &= 0xffff0000;
171 	ttbufs.c_lflag &= 0xffff0000;
172 #ifdef PKSPEEDUP
173 	linebaudrate = spwant;
174 #endif /*  PKSPEEDUP  */
175 
176 #ifdef NO_MODEM_CTRL
177 	/*   CLOCAL may cause problems on pdp11s with DHs */
178 	if (type == D_DIRECT) {
179 		DEBUG(4, "fixline - direct\n%s", "");
180 		ttbufs.c_cflag |= CLOCAL;
181 	} else
182 #endif /* NO_MODEM_CTRL */
183 		ttbufs.c_cflag &= ~CLOCAL;
184 
185 	if (!EQUALS(Progname, "uucico")) {
186 
187 		/* set attributes associated with -h, -t, -e, and -o options */
188 
189 		ttbufs.c_iflag = (IGNPAR | IGNBRK | IXON | IXOFF);
190 		ttbufs.c_cc[VEOF] = '\1';
191 		ttbufs.c_cflag |= (CREAD | (speed ? HUPCL : 0));
192 
193 		if (line_8bit) {
194 			ttbufs.c_cflag |= CS8;
195 			ttbufs.c_iflag &= ~ISTRIP;
196 		} else {
197 			if (Evenflag) {			/* even parity -e */
198 				ttbufs.c_cflag &= ~PARODD;
199 			} else if (Oddflag) {		/* odd parity -o */
200 				ttbufs.c_cflag |= PARODD;
201 			}
202 			ttbufs.c_cflag |= CS7|PARENB;
203 			ttbufs.c_iflag |= ISTRIP;
204 		}
205 
206 		if (!Duplex)				/* half duplex -h */
207 			ttbufs.c_iflag &= ~(IXON | IXOFF);
208 		if (Terminal)				/* -t */
209 			ttbufs.c_oflag |= (OPOST | ONLCR);
210 
211 	} else { /* non-uucico */
212 		ttbufs.c_cflag |= (CS8 | CREAD | (speed ? HUPCL : 0));
213 		ttbufs.c_cc[VMIN] = HEADERSIZE;
214 		ttbufs.c_cc[VTIME] = 1;
215 	}
216 
217 	if (istermios < 0) {
218 		ttbuf.c_lflag = ttbufs.c_lflag;
219 		ttbuf.c_oflag = ttbufs.c_oflag;
220 		ttbuf.c_iflag = ttbufs.c_iflag;
221 		ttbuf.c_cflag = ttbufs.c_cflag;
222 		for (i = 0; i < NCC; i++)
223 			ttbuf.c_cc[i] = ttbufs.c_cc[i];
224 		ASSERT((*Ioctl)(tty, TCSETAW, &ttbuf) >= 0,
225 		    "RETURN FROM fixline ioctl", "", errno);
226 	} else {
227 		ASSERT((*Ioctl)(tty, TCSETSW, &ttbufs) >= 0,
228 		    "RETURN FROM fixline ioctl", "", errno);
229 	}
230 }
231 
232 GLOBAL void
233 sethup(dcf)
234 int	dcf;
235 {
236 	struct termio ttbuf;
237 
238 	if ((*Ioctl)(dcf, TCGETA, &ttbuf) != 0)
239 		return;
240 	if (!(ttbuf.c_cflag & HUPCL)) {
241 		ttbuf.c_cflag |= HUPCL;
242 		(void) (*Ioctl)(dcf, TCSETAW, &ttbuf);
243 	}
244 }
245 
246 GLOBAL void
247 ttygenbrk(fn)
248 register int	fn;
249 {
250 	if (isatty(fn))
251 		(void) (*Ioctl)(fn, TCSBRK, 0);
252 }
253 
254 
255 /*
256  * optimize line setting for sending or receiving files
257  * return:
258  *	none
259  */
260 GLOBAL void
261 setline(type)
262 register char	type;
263 {
264 	static struct termio tbuf;
265 	static struct termios tbufs;
266 	int i, vtime, istermios, ospeed;
267 
268 	DEBUG(2, "setline - %c\n", type);
269 
270 	if ((istermios = (*Ioctl)(Ifn, TCGETS, &tbufs)) < 0) {
271 		if ((*Ioctl)(Ifn, TCGETA, &tbuf) != 0) {
272 			return;
273 		} else {
274 			tbufs.c_lflag = tbuf.c_lflag;
275 			tbufs.c_oflag = tbuf.c_oflag;
276 			tbufs.c_iflag = tbuf.c_iflag;
277 			tbufs.c_cflag = tbuf.c_cflag;
278 			for (i = 0; i < NCC; i++)
279 				tbufs.c_cc[i] = tbuf.c_cc[i];
280 		}
281 	}
282 	switch (type) {
283 	case RCVFILE:
284 		ospeed = cfgetospeed(&tbufs);
285 		switch (ospeed) {
286 #ifdef B19200
287 		case B19200:
288 #else
289 #ifdef EXTA
290 		case EXTA:
291 #endif
292 #endif
293 #ifdef B38400
294 		case B38400:
295 #endif
296 		case B57600:
297 		case B76800:
298 		case B115200:
299 		case B153600:
300 		case B230400:
301 		case B307200:
302 		case B460800:
303 		case B921600:
304 		case B9600:
305 			vtime = 1;
306 			break;
307 		case B4800:
308 			vtime = 4;
309 			break;
310 		default:
311 			vtime = 8;
312 			break;
313 		}
314 		if (tbufs.c_cc[VMIN] != packsize ||
315 		    tbufs.c_cc[VTIME] != vtime) {
316 		    tbufs.c_cc[VMIN] = packsize;
317 		    tbufs.c_cc[VTIME] = vtime;
318 		    if (istermios < 0) {
319 			tbuf.c_lflag = tbufs.c_lflag;
320 			tbuf.c_oflag = tbufs.c_oflag;
321 			tbuf.c_iflag = tbufs.c_iflag;
322 			tbuf.c_cflag = tbufs.c_cflag;
323 			for (i = 0; i < NCC; i++)
324 				tbuf.c_cc[i] = tbufs.c_cc[i];
325 			if ((*Ioctl)(Ifn, TCSETAW, &tbuf) != 0)
326 				DEBUG(4, "setline Ioctl failed errno=%d\n",
327 				    errno);
328 			} else {
329 				if ((*Ioctl)(Ifn, TCSETSW, &tbufs) != 0)
330 					DEBUG(4,
331 					    "setline Ioctl failed errno=%d\n",
332 					    errno);
333 			}
334 		}
335 		break;
336 
337 	case SNDFILE:
338 	case RESET:
339 		if (tbufs.c_cc[VMIN] != HEADERSIZE) {
340 			tbufs.c_cc[VMIN] = HEADERSIZE;
341 			if (istermios < 0) {
342 				tbuf.c_lflag = tbufs.c_lflag;
343 				tbuf.c_oflag = tbufs.c_oflag;
344 				tbuf.c_iflag = tbufs.c_iflag;
345 				tbuf.c_cflag = tbufs.c_cflag;
346 				for (i = 0; i < NCC; i++)
347 					tbuf.c_cc[i] = tbufs.c_cc[i];
348 				if ((*Ioctl)(Ifn, TCSETAW, &tbuf) != 0)
349 					DEBUG(4,
350 					    "setline Ioctl failed errno=%d\n",
351 					    errno);
352 			} else {
353 				if ((*Ioctl)(Ifn, TCSETSW, &tbufs) != 0)
354 					DEBUG(4,
355 					    "setline Ioctl failed errno=%d\n",
356 					    errno);
357 			}
358 		}
359 		break;
360 	}
361 }
362 
363 GLOBAL int
364 savline()
365 {
366 	if ((Saved_termios = (*Ioctl)(0, TCGETS, &Savettybs)) < 0) {
367 		if ((*Ioctl)(0, TCGETA, &Savettyb) != 0) {
368 			Saved_line = FALSE;
369 		} else {
370 			Saved_line = TRUE;
371 			Savettyb.c_cflag =
372 			    (Savettyb.c_cflag & ~CS8) | CS7 | PARENB;
373 			Savettyb.c_oflag |= OPOST;
374 			Savettyb.c_lflag |= (ISIG|ICANON|ECHO);
375 		}
376 	} else {
377 		Saved_line = TRUE;
378 		Savettybs.c_cflag = (Savettybs.c_cflag & ~CS8) | CS7 | PARENB;
379 		Savettybs.c_oflag |= OPOST;
380 		Savettybs.c_lflag |= (ISIG|ICANON|ECHO);
381 	}
382 	return (0);
383 }
384 
385 #ifdef SYTEK
386 
387 /*
388  *	sytfixline(tty, spwant)	set speed/echo/mode...
389  *	int tty, spwant;
390  *
391  *	return codes:  none
392  */
393 
394 GLOBAL void
395 sytfixline(tty, spwant)
396 int tty, spwant;
397 {
398 	struct termio ttbuf;
399 	struct termios ttbufs;
400 	struct sg_spds *ps;
401 	int speed = -1;
402 	int i, ret, istermios;
403 
404 	if ((istermios = (*Ioctl)(tty, TCGETS, &ttbufs)) < 0) {
405 		if ((*Ioctl)(tty, TCGETA, &ttbuf) != 0) {
406 			return;
407 		} else {
408 			ttbufs.c_lflag = ttbuf.c_lflag;
409 			ttbufs.c_oflag = ttbuf.c_oflag;
410 			ttbufs.c_iflag = ttbuf.c_iflag;
411 			ttbufs.c_cflag = ttbuf.c_cflag;
412 			for (i = 0; i < NCC; i++)
413 				ttbufs.c_cc[i] = ttbuf.c_cc[i];
414 		}
415 	}
416 	for (ps = spds; ps->sp_val >= 0; ps++)
417 		if (ps->sp_val == spwant)
418 			speed = ps->sp_name;
419 	DEBUG(4, "sytfixline - speed= %d\n", speed);
420 	ASSERT(speed >= 0, "BAD SPEED", "", spwant);
421 	ttbufs.c_iflag &= 0xffff0000;
422 	ttbufs.c_oflag &= 0xffff0000;
423 	ttbufs.c_lflag &= 0xffff0000;
424 	ttbufs.c_cflag &= 0xffff0000;
425 	cfsetospeed(&ttbufs, speed);
426 	ttbufs.c_cflag |= (CS8|CLOCAL);
427 	ttbufs.c_cc[VMIN] = 6;
428 	ttbufs.c_cc[VTIME] = 1;
429 	if (istermios < 0) {
430 		ttbuf.c_lflag = ttbufs.c_lflag;
431 		ttbuf.c_oflag = ttbufs.c_oflag;
432 		ttbuf.c_iflag = ttbufs.c_iflag;
433 		ttbuf.c_cflag = ttbufs.c_cflag;
434 		for (i = 0; i < NCC; i++)
435 			ttbuf.c_cc[i] = ttbufs.c_cc[i];
436 		ret = (*Ioctl)(tty, TCSETAW, &ttbuf);
437 	} else
438 		ret = (*Ioctl)(tty, TCSETAWS &ttbufs);
439 	ASSERT(ret >= 0, "RETURN FROM sytfixline", "", ret);
440 }
441 
442 GLOBAL void
443 sytfix2line(tty)
444 int tty;
445 {
446 	struct termio ttbuf;
447 	int ret;
448 
449 	if ((*Ioctl)(tty, TCGETA, &ttbuf) != 0)
450 		return;
451 	ttbuf.c_cflag &= ~CLOCAL;
452 	ttbuf.c_cflag |= CREAD|HUPCL;
453 	ret = (*Ioctl)(tty, TCSETAW, &ttbuf);
454 	ASSERT(ret >= 0, "RETURN FROM sytfix2line", "", ret);
455 }
456 
457 #endif /* SYTEK */
458 
459 GLOBAL int
460 restline()
461 {
462 	if (Saved_line == TRUE) {
463 		if (Saved_termios < 0)
464 			return ((*Ioctl)(0, TCSETAW, &Savettyb));
465 		else
466 			return ((*Ioctl)(0, TCSETSW, &Savettybs));
467 	}
468 	return (0);
469 }
470 
471 #else /* !ATTSVTTY */
472 
473 static struct sgttyb Savettyb;
474 
475 /*
476  *	fixline(tty, spwant, type)	set speed/echo/mode...
477  *	int tty, spwant;
478  *
479  *	if spwant == 0, speed is untouched
480  *	type is unused, but needed for compatibility
481  *
482  *	return codes:  none
483  */
484 
485 /*ARGSUSED*/
486 GLOBAL void
487 fixline(tty, spwant, type)
488 int tty, spwant, type;
489 {
490 	struct sgttyb	ttbuf;
491 	struct sg_spds	*ps;
492 	int		 speed = -1;
493 
494 	DEBUG(6, "fixline(%d, ", tty);
495 	DEBUG(6, "%d)\n", spwant);
496 
497 	if ((*Ioctl)(tty, TIOCGETP, &ttbuf) != 0)
498 		return;
499 	if (spwant > 0) {
500 		for (ps = spds; ps->sp_val; ps++)
501 			if (ps->sp_val == spwant) {
502 				speed = ps->sp_name;
503 				break;
504 			}
505 		ASSERT(speed >= 0, "BAD SPEED", "", spwant);
506 		ttbuf.sg_ispeed = ttbuf.sg_ospeed = speed;
507 	} else {
508 		for (ps = spds; ps->sp_val; ps++)
509 			if (ps->sp_name == ttbuf.sg_ispeed) {
510 				spwant = ps->sp_val;
511 				break;
512 			}
513 		ASSERT(spwant >= 0, "BAD SPEED", "", ttbuf.sg_ispeed);
514 	}
515 	ttbuf.sg_flags = (ANYP | RAW);
516 #ifdef PKSPEEDUP
517 	linebaudrate = spwant;
518 #endif /*  PKSPEEDUP  */
519 	(void) (*Ioctl)(tty, TIOCSETP, &ttbuf);
520 	(void) (*Ioctl)(tty, TIOCHPCL, STBNULL);
521 	(void) (*Ioctl)(tty, TIOCEXCL, STBNULL);
522 }
523 
524 GLOBAL void
525 sethup(dcf)
526 int	dcf;
527 {
528 	if (isatty(dcf))
529 		(void) (*Ioctl)(dcf, TIOCHPCL, STBNULL);
530 }
531 
532 /*
533  *	genbrk		send a break
534  *
535  *	return codes;  none
536  */
537 
538 GLOBAL void
539 ttygenbrk(fn)
540 {
541 	if (isatty(fn)) {
542 		(void) (*Ioctl)(fn, TIOCSBRK, 0);
543 #ifndef V8
544 		nap(HZ/10);				/* 0.1 second break */
545 		(void) (*Ioctl)(fn, TIOCCBRK, 0);
546 #endif
547 	}
548 }
549 
550 /*
551  * V7 and RT aren't smart enough for this -- linebaudrate is the best
552  * they can do.
553  */
554 /*ARGSUSED*/
555 GLOBAL void
556 setline(dummy) { }
557 
558 GLOBAL int
559 savline()
560 {
561 	if ((*Ioctl)(0, TIOCGETP, &Savettyb) != 0)
562 		Saved_line = FALSE;
563 	else {
564 		Saved_line = TRUE;
565 		Savettyb.sg_flags |= ECHO;
566 		Savettyb.sg_flags &= ~RAW;
567 	}
568 	return (0);
569 }
570 
571 GLOBAL int
572 restline()
573 {
574 	if (Saved_line == TRUE)
575 		return ((*Ioctl)(0, TIOCSETP, &Savettyb));
576 	return (0);
577 }
578 #endif
579