xref: /csrg-svn/sys/kern/tty.c (revision 728)
1 /*	tty.c	3.13	08/27/80	*/
2 
3 /*
4  * general TTY subroutines
5  */
6 #include "../h/param.h"
7 #include "../h/systm.h"
8 #include "../h/dir.h"
9 #include "../h/user.h"
10 #include "../h/tty.h"
11 #include "../h/proc.h"
12 #include "../h/mx.h"
13 #include "../h/inode.h"
14 #include "../h/file.h"
15 #include "../h/reg.h"
16 #include "../h/conf.h"
17 #include "../h/buf.h"
18 #include "../h/dk.h"
19 
20 char	partab[];
21 
22 /*
23  * When running dz's using only SAE (silo alarm) on input
24  * it is necessary to call dzrint() at clock interrupt time.
25  * This is unsafe unless spl5()s in tty code are changed to
26  * spl6()s to block clock interrupts.  Note that the dh driver
27  * currently in use works the same way as the dz, even though
28  * we could try to more intelligently manage its silo.
29  * Thus don't take this out if you have no dz's unless you
30  * change clock.c and dhtimer().
31  */
32 #define	spl5	spl6
33 
34 /*
35  * Input mapping table-- if an entry is non-zero, when the
36  * corresponding character is typed preceded by "\" the escape
37  * sequence is replaced by the table value.  Mostly used for
38  * upper-case only terminals.
39  */
40 
41 char	maptab[] ={
42 	000,000,000,000,000,000,000,000,
43 	000,000,000,000,000,000,000,000,
44 	000,000,000,000,000,000,000,000,
45 	000,000,000,000,000,000,000,000,
46 	000,'|',000,000,000,000,000,'`',
47 	'{','}',000,000,000,000,000,000,
48 	000,000,000,000,000,000,000,000,
49 	000,000,000,000,000,000,000,000,
50 	000,000,000,000,000,000,000,000,
51 	000,000,000,000,000,000,000,000,
52 	000,000,000,000,000,000,000,000,
53 	000,000,000,000,000,000,'~',000,
54 	000,'A','B','C','D','E','F','G',
55 	'H','I','J','K','L','M','N','O',
56 	'P','Q','R','S','T','U','V','W',
57 	'X','Y','Z',000,000,000,000,000,
58 };
59 
60 
61 /*
62  * shorthand
63  */
64 #define	q1	tp->t_rawq
65 #define	q2	tp->t_canq
66 #define	q3	tp->t_outq
67 #define	q4	tp->t_un.t_ctlq
68 
69 #define	OBUFSIZ	100
70 
71 /*
72  * routine called on first teletype open.
73  * establishes a process group for distribution
74  * of quits and interrupts from the tty.
75  */
76 ttyopen(dev, tp)
77 dev_t dev;
78 register struct tty *tp;
79 {
80 	register struct proc *pp;
81 
82 	pp = u.u_procp;
83 	tp->t_dev = dev;
84 	if(pp->p_pgrp == 0) {
85 		u.u_ttyp = tp;
86 		u.u_ttyd = dev;
87 		if (tp->t_pgrp == 0)
88 			tp->t_pgrp = pp->p_pid;
89 		pp->p_pgrp = tp->t_pgrp;
90 	}
91 	tp->t_state &= ~WOPEN;
92 	tp->t_state |= ISOPEN;
93 	tp->t_line = 0;		/* conservative */
94 }
95 
96 /*
97  * set default control characters.
98  */
99 ttychars(tp)
100 register struct tty *tp;
101 {
102 
103 	tun.t_intrc = CINTR;
104 	tun.t_quitc = CQUIT;
105 	tun.t_startc = CSTART;
106 	tun.t_stopc = CSTOP;
107 	tun.t_eofc = CEOT;
108 	tun.t_brkc = CBRK;
109 	tp->t_erase = CERASE;
110 	tp->t_kill = CKILL;
111 /* begin local */
112 	tlun.t_suspc = CTRL(z);
113 	tlun.t_dsuspc = CTRL(y);
114 	tlun.t_rprntc = CTRL(r);
115 	tlun.t_flushc = CTRL(o);
116 	tlun.t_werasc = CTRL(w);
117 	tlun.t_lnextc = CTRL(v);
118 	tlun.t_lintr = CTRL(c);
119 	tlun.t_lerase = CTRL(h);
120 	tlun.t_lkill = CTRL(u);
121 	tp->t_local = 0;
122 	tp->t_lstate = 0;
123 /* end local */
124 }
125 
126 /*
127  * clean tp on last close
128  */
129 ttyclose(tp)
130 register struct tty *tp;
131 {
132 
133 	tp->t_pgrp = 0;
134 	wflushtty(tp);
135 	tp->t_state = 0;
136 	tp->t_line = 0;
137 }
138 
139 /*
140  * stty/gtty writearound
141  */
142 stty()
143 {
144 	u.u_arg[2] = u.u_arg[1];
145 	u.u_arg[1] = TIOCSETP;
146 	ioctl();
147 }
148 
149 gtty()
150 {
151 	u.u_arg[2] = u.u_arg[1];
152 	u.u_arg[1] = TIOCGETP;
153 	ioctl();
154 }
155 
156 /*
157  * Do nothing specific version of line
158  * discipline specific ioctl command.
159  */
160 /*ARGSUSED*/
161 nullioctl(tp, cmd, addr)
162 register struct tty *tp;
163 caddr_t addr;
164 {
165 
166 	return (cmd);
167 }
168 
169 /*
170  * ioctl system call
171  * Check legality, execute common code, and switch out to individual
172  * device routine.
173  */
174 ioctl()
175 {
176 	register struct file *fp;
177 	register struct inode *ip;
178 	register struct a {
179 		int	fdes;
180 		int	cmd;
181 		caddr_t	cmarg;
182 	} *uap;
183 	register dev_t dev;
184 	register fmt;
185 
186 	uap = (struct a *)u.u_ap;
187 	if ((fp = getf(uap->fdes)) == NULL)
188 		return;
189 	if (uap->cmd==FIOCLEX) {
190 		u.u_pofile[uap->fdes] |= EXCLOSE;
191 		return;
192 	}
193 	if (uap->cmd==FIONCLEX) {
194 		u.u_pofile[uap->fdes] &= ~EXCLOSE;
195 		return;
196 	}
197 	ip = fp->f_inode;
198 	fmt = ip->i_mode & IFMT;
199 	if (fmt != IFCHR && fmt != IFMPC) {
200 /* begin local */
201 		if (uap->cmd==FIONREAD && (fmt == IFREG || fmt == IFDIR)) {
202 			off_t nread = ip->i_size - fp->f_un.f_offset;
203 
204 			if (copyout((caddr_t)&nread, uap->cmarg, sizeof(off_t)))
205 				u.u_error = EFAULT;
206 		} else
207 /* end local */
208 			u.u_error = ENOTTY;
209 		return;
210 	}
211 	dev = ip->i_un.i_rdev;
212 	u.u_r.r_val1 = 0;
213 	(*cdevsw[major(dev)].d_ioctl)(dev, uap->cmd, uap->cmarg, fp->f_flag);
214 }
215 
216 /*
217  * Common code for several tty ioctl commands
218  */
219 ttioccomm(com, tp, addr, dev)
220 register struct tty *tp;
221 caddr_t addr;
222 {
223 	unsigned t;
224 	struct sgttyb iocb;
225 	struct clist tq;
226 	extern int nldisp;
227 	int temp;
228 
229 	switch(com) {
230 
231 	/*
232 	 * get discipline number
233 	 */
234 	case TIOCGETD:
235 		t = tp->t_line;
236 		if (copyout((caddr_t)&t, addr, sizeof(t)))
237 			u.u_error = EFAULT;
238 		break;
239 
240 	/*
241 	 * set line discipline
242 	 */
243 	case TIOCSETD:
244 		if (copyin(addr, (caddr_t)&t, sizeof(t))) {
245 			u.u_error = EFAULT;
246 			break;
247 		}
248 		if (t >= nldisp) {
249 			u.u_error = ENXIO;
250 			break;
251 		}
252 		(void) spl5();
253 		if (tp->t_line)
254 			(*linesw[tp->t_line].l_close)(tp);
255 		if (t)
256 			(*linesw[t].l_open)(dev, tp, addr);
257 		if (u.u_error==0)
258 			tp->t_line = t;
259 		(void) spl0();
260 		break;
261 
262 	/*
263 	 * prevent more opens on channel
264 	 */
265 	case TIOCEXCL:
266 		tp->t_state |= XCLUDE;
267 		break;
268 
269 	case TIOCNXCL:
270 		tp->t_state &= ~XCLUDE;
271 		break;
272 
273 	/*
274 	 * Set new parameters
275 	 */
276 	case TIOCSETP:
277 	case TIOCSETN:
278 		if (copyin(addr, (caddr_t)&iocb, sizeof(iocb))) {
279 			u.u_error = EFAULT;
280 			return(1);
281 		}
282 		(void) spl5();
283 		if (tp->t_line == 0) {
284 			if (com == TIOCSETP)
285 				wflushtty(tp);
286 			while (canon(tp)>=0)
287 				;
288 		} else if (tp->t_line == NTTYDISC) {
289 			if (tp->t_flags&RAW || iocb.sg_flags&RAW ||
290 			    com == TIOCSETP)
291 				wflushtty(tp);
292 			else if ((tp->t_flags&CBREAK) != (iocb.sg_flags&CBREAK)) {
293 				if (iocb.sg_flags & CBREAK) {
294 					catq(&tp->t_rawq, &tp->t_canq);
295 					tq = tp->t_rawq;
296 					tp->t_rawq = tp->t_canq;
297 					tp->t_canq = tq;
298 				} else {
299 					tp->t_local |= LPENDIN;
300 					if (tp->t_canq.c_cc)
301 						panic("ioccom canq");
302 					if (tp->t_chan)
303 						(void) sdata(tp->t_chan);
304 					else
305 						wakeup((caddr_t)&tp->t_rawq);
306 				}
307 			}
308 		}
309 		if ((tp->t_state&SPEEDS)==0) {
310 			tp->t_ispeed = iocb.sg_ispeed;
311 			tp->t_ospeed = iocb.sg_ospeed;
312 		}
313 		tp->t_erase = iocb.sg_erase;
314 		tp->t_kill = iocb.sg_kill;
315 		tp->t_flags = iocb.sg_flags;
316 		(void) spl0();
317 		break;
318 
319 	/*
320 	 * send current parameters to user
321 	 */
322 	case TIOCGETP:
323 		iocb.sg_ispeed = tp->t_ispeed;
324 		iocb.sg_ospeed = tp->t_ospeed;
325 		iocb.sg_erase = tp->t_erase;
326 		iocb.sg_kill = tp->t_kill;
327 		iocb.sg_flags = tp->t_flags;
328 		if (copyout((caddr_t)&iocb, addr, sizeof(iocb)))
329 			u.u_error = EFAULT;
330 		break;
331 
332 	/*
333 	 * Hang up line on last close
334 	 */
335 
336 	case TIOCHPCL:
337 		tp->t_state |= HUPCLS;
338 		break;
339 
340 	case TIOCFLUSH:
341 		flushtty(tp);
342 		break;
343 
344 	/*
345 	 * ioctl entries to line discipline
346 	 */
347 	case DIOCSETP:
348 	case DIOCGETP:
349 		if ((*linesw[tp->t_line].l_ioctl)(com, tp, addr))
350 			u.u_error = ENOTTY;
351 		break;
352 
353 	/*
354 	 * set and fetch special characters
355 	 */
356 	case TIOCSETC:
357 		if (copyin(addr, (caddr_t)&tun, sizeof(struct tchars)))
358 			u.u_error = EFAULT;
359 		break;
360 
361 	case TIOCGETC:
362 		if (copyout((caddr_t)&tun, addr, sizeof(struct tchars)))
363 			u.u_error = EFAULT;
364 		break;
365 
366 /* local ioctls */
367 	case TIOCSLTC:
368 		if (copyin(addr, (caddr_t)&tlun, sizeof (struct ltchars)))
369 			u.u_error = EFAULT;
370 		break;
371 
372 	case TIOCGLTC:
373 		if (copyout((caddr_t)&tlun, addr, sizeof (struct ltchars)))
374 			u.u_error = EFAULT;
375 		break;
376 
377 	case FIONREAD: {
378 		off_t nread;
379 
380 		switch (tp->t_line) {
381 
382 		case NETLDISC:
383 			nread = tp->t_rec ? tp->t_inbuf : 0;
384 			break;
385 
386 		case NTTYDISC:
387 			nread = tp->t_canq.c_cc;
388 			if (tp->t_flags & (RAW|CBREAK))
389 				nread += tp->t_rawq.c_cc;
390 			break;
391 
392 		case 0:
393 			/* do something here ... */
394 			;
395 		}
396 		if (copyout((caddr_t)&nread, addr, sizeof (off_t)))
397 			u.u_error = EFAULT;
398 		break;
399 		}
400 
401 	/*
402 	 * Should allow SPGRP and GPGRP only if tty open for reading.
403 	 */
404 	case TIOCSPGRP:
405 		if (copyin(addr, (caddr_t)&tp->t_pgrp, sizeof (tp->t_pgrp)))
406 			u.u_error = EFAULT;
407 		break;
408 
409 	case TIOCGPGRP:
410 		if (copyout((caddr_t)&tp->t_pgrp, addr, sizeof(tp->t_pgrp)))
411 			u.u_error = EFAULT;
412 		break;
413 
414 	/*
415 	 * Modify local mode word.
416 	 */
417 	case TIOCLBIS:
418 		if (copyin(addr, (caddr_t)&temp, sizeof (tp->t_local)))
419 			u.u_error = EFAULT;
420 		else
421 			tp->t_local |= temp;
422 		break;
423 
424 	case TIOCLBIC:
425 		if (copyin(addr, (caddr_t)&temp, sizeof (tp->t_local)))
426 			u.u_error = EFAULT;
427 		else
428 			tp->t_local &= ~temp;
429 		break;
430 
431 	case TIOCLSET:
432 		if (copyin(addr, (caddr_t)&temp, sizeof (tp->t_local)))
433 			u.u_error = EFAULT;
434 		else
435 			tp->t_local = temp;
436 		break;
437 
438 	case TIOCLGET:
439 		if (copyout((caddr_t)&tp->t_local, addr, sizeof(tp->t_local)))
440 			u.u_error = EFAULT;
441 		break;
442 
443 	case TIOCOUTQ:
444 		if (copyout((caddr_t)&tp->t_outq.c_cc, addr, sizeof(tp->t_outq.c_cc)))
445 			u.u_error = EFAULT;
446 		break;
447 
448 /* end of locals */
449 	default:
450 		return(0);
451 	}
452 	return(1);
453 }
454 
455 /*
456  * Wait for output to drain, then flush input waiting.
457  */
458 wflushtty(tp)
459 register struct tty *tp;
460 {
461 
462 	(void) spl5();
463 	while (tp->t_outq.c_cc && tp->t_state&CARR_ON) {
464 		(*tp->t_oproc)(tp);
465 		tp->t_state |= ASLEEP;
466 		sleep((caddr_t)&tp->t_outq, TTOPRI);
467 	}
468 	flushtty(tp);
469 	(void) spl0();
470 }
471 
472 /*
473  * flush all TTY queues
474  */
475 flushtty(tp)
476 register struct tty *tp;
477 {
478 	register s;
479 
480 	if (tp->t_line == NETLDISC)
481 		return;
482 	s = spl6();
483 	while (getc(&tp->t_canq) >= 0)
484 		;
485 	wakeup((caddr_t)&tp->t_rawq);
486 	wakeup((caddr_t)&tp->t_outq);
487 	tp->t_state &= ~TTSTOP;
488 	(*cdevsw[major(tp->t_dev)].d_stop)(tp);
489 	while (getc(&tp->t_outq) >= 0)
490 		;
491 	while (getc(&tp->t_rawq) >= 0)
492 		;
493 	tp->t_delct = 0;
494 	tp->t_rocount = 0;		/* local */
495 	tp->t_lstate = 0;
496 	splx(s);
497 }
498 
499 
500 
501 /*
502  * transfer raw input list to canonical list,
503  * doing erase-kill processing and handling escapes.
504  * It waits until a full line has been typed in cooked mode,
505  * or until any character has been typed in raw mode.
506  */
507 canon(tp)
508 register struct tty *tp;
509 {
510 	register char *bp;
511 	char *bp1;
512 	register int c;
513 	int mc;
514 	int s;
515 
516 	if ((tp->t_flags&(RAW|CBREAK))==0 && tp->t_delct==0
517 	    || (tp->t_flags&(RAW|CBREAK))!=0 && tp->t_rawq.c_cc==0) {
518 		return(-1);
519 	}
520 	s = spl0();
521 loop:
522 	bp = &canonb[2];
523 	while ((c=getc(&tp->t_rawq)) >= 0) {
524 		if ((tp->t_flags&(RAW|CBREAK))==0) {
525 			if (c==0377) {
526 				tp->t_delct--;
527 				break;
528 			}
529 			if (bp[-1]!='\\') {
530 				if (c==tp->t_erase) {
531 					if (bp > &canonb[2])
532 						bp--;
533 					continue;
534 				}
535 				if (c==tp->t_kill)
536 					goto loop;
537 				if (c==tun.t_eofc)
538 					continue;
539 			} else {
540 				mc = maptab[c];
541 				if (c==tp->t_erase || c==tp->t_kill)
542 					mc = c;
543 				if (mc && (mc==c || (tp->t_flags&LCASE))) {
544 					if (bp[-2] != '\\')
545 						c = mc;
546 					bp--;
547 				}
548 			}
549 		}
550 		*bp++ = c;
551 		if (bp>=canonb+CANBSIZ)
552 			break;
553 	}
554 	bp1 = &canonb[2];
555 	(void) b_to_q(bp1, bp-bp1, &tp->t_canq);
556 
557 	if (tp->t_state&TBLOCK && tp->t_rawq.c_cc < TTYHOG/5) {
558 		if (putc(tun.t_startc, &tp->t_outq)==0) {
559 			tp->t_state &= ~TBLOCK;
560 			ttstart(tp);
561 		}
562 		tp->t_char = 0;
563 	}
564 
565 	splx(s);
566 	return(0);
567 }
568 
569 
570 /*
571  * block transfer input handler.
572  */
573 ttyrend(tp, pb, pe)
574 register struct tty *tp;
575 register char *pb, *pe;
576 {
577 	int	tandem;
578 
579 	tandem = tp->t_flags&TANDEM;
580 	if (tp->t_flags&RAW) {
581 		(void) b_to_q(pb, pe-pb, &tp->t_rawq);
582 		if (tp->t_chan)
583 			(void) sdata(tp->t_chan); else
584 			wakeup((caddr_t)&tp->t_rawq);
585 	} else {
586 		tp->t_flags &= ~TANDEM;
587 		while (pb < pe)
588 			ttyinput(*pb++, tp);
589 		tp->t_flags |= tandem;
590 	}
591 	if (tandem)
592 		ttyblock(tp);
593 }
594 
595 /*
596  * Place a character on raw TTY input queue, putting in delimiters
597  * and waking up top half as needed.
598  * Also echo if required.
599  * The arguments are the character and the appropriate
600  * tty structure.
601  */
602 ttyinput(c, tp)
603 register c;
604 register struct tty *tp;
605 {
606 	register int t_flags;
607 	register struct chan *cp;
608 
609 	tk_nin += 1;
610 	c &= 0377;
611 	t_flags = tp->t_flags;
612 	if (t_flags&TANDEM)
613 		ttyblock(tp);
614 	if ((t_flags&RAW)==0) {
615 		c &= 0177;
616 		if (tp->t_state&TTSTOP) {
617 			if (c==tun.t_startc) {
618 				tp->t_state &= ~TTSTOP;
619 				ttstart(tp);
620 				return;
621 			}
622 			if (c==tun.t_stopc)
623 				return;
624 			tp->t_state &= ~TTSTOP;
625 			ttstart(tp);
626 		} else {
627 			if (c==tun.t_stopc) {
628 				tp->t_state |= TTSTOP;
629 				(*cdevsw[major(tp->t_dev)].d_stop)(tp);
630 				return;
631 			}
632 			if (c==tun.t_startc)
633 				return;
634 		}
635 		if (c==tun.t_quitc || c==tun.t_intrc) {
636 			flushtty(tp);
637 			c = (c==tun.t_intrc) ? SIGINT:SIGQUIT;
638 			if (tp->t_chan)
639 				scontrol(tp->t_chan, M_SIG, c);
640 			else
641 				gsignal(tp->t_pgrp, c);
642 			return;
643 		}
644 		if (c=='\r' && t_flags&CRMOD)
645 			c = '\n';
646 	}
647 	if (tp->t_rawq.c_cc>TTYHOG) {
648 		flushtty(tp);
649 		return;
650 	}
651 	if (t_flags&LCASE && c>='A' && c<='Z')
652 		c += 'a'-'A';
653 	(void) putc(c, &tp->t_rawq);
654 	if (t_flags&(RAW|CBREAK)||(c=='\n'||c==tun.t_eofc||c==tun.t_brkc)) {
655 		if ((t_flags&(RAW|CBREAK))==0 && putc(0377, &tp->t_rawq)==0)
656 			tp->t_delct++;
657 		if ((cp=tp->t_chan)!=NULL)
658 			(void) sdata(cp); else
659 			wakeup((caddr_t)&tp->t_rawq);
660 	}
661 	if (t_flags&ECHO) {
662 		ttyoutput(c, tp);
663 		if (c==tp->t_kill && (t_flags&(RAW|CBREAK))==0)
664 			ttyoutput('\n', tp);
665 		ttstart(tp);
666 	}
667 }
668 
669 
670 /*
671  * Send stop character on input overflow.
672  */
673 ttyblock(tp)
674 register struct tty *tp;
675 {
676 	register x;
677 	x = q1.c_cc + q2.c_cc;
678 	if (q1.c_cc > TTYHOG) {
679 		flushtty(tp);
680 		tp->t_state &= ~TBLOCK;
681 	}
682 	if (x >= TTYHOG/2) {
683 		if (putc(tun.t_stopc, &tp->t_outq)==0) {
684 			tp->t_state |= TBLOCK;
685 			tp->t_char++;
686 			ttstart(tp);
687 		}
688 	}
689 }
690 
691 /*
692  * put character on TTY output queue, adding delays,
693  * expanding tabs, and handling the CR/NL bit.
694  * It is called both from the top half for output, and from
695  * interrupt level for echoing.
696  * The arguments are the character and the tty structure.
697  */
698 ttyoutput(c, tp)
699 register c;
700 register struct tty *tp;
701 {
702 	register char *colp;
703 	register ctype;
704 
705 	/*
706 	 * Ignore EOT in normal mode to avoid hanging up
707 	 * certain terminals.
708 	 * In raw mode dump the char unchanged.
709 	 */
710 	if ((tp->t_flags&RAW)==0) {
711 		c &= 0177;
712 		if ((tp->t_flags&CBREAK)==0 && c==CEOT)
713 			return;
714 	} else {
715 		tk_nout++;
716 		(void) putc(c, &tp->t_outq);
717 		return;
718 	}
719 
720 	/*
721 	 * Turn tabs to spaces as required
722 	 */
723 	if (c=='\t' && (tp->t_flags&TBDELAY)==XTABS) {
724 		c = 8 - (tp->t_col & 7);
725 		(void) b_to_q("        ", c, &tp->t_outq);
726 		tp->t_col += c;
727 		tk_nout += c;
728 		return;
729 	}
730 	tk_nout++;
731 	/*
732 	 * for upper-case-only terminals,
733 	 * generate escapes.
734 	 */
735 	if (tp->t_flags&LCASE) {
736 		colp = "({)}!|^~'`";
737 		while(*colp++)
738 			if(c == *colp++) {
739 				ttyoutput('\\', tp);
740 				c = colp[-2];
741 				break;
742 			}
743 		if ('a'<=c && c<='z')
744 			c += 'A' - 'a';
745 	}
746 	/*
747 	 * turn <nl> to <cr><lf> if desired.
748 	 */
749 	if (c=='\n' && tp->t_flags&CRMOD)
750 		ttyoutput('\r', tp);
751 	(void) putc(c, &tp->t_outq);
752 	/*
753 	 * Calculate delays.
754 	 * The numbers here represent clock ticks
755 	 * and are not necessarily optimal for all terminals.
756 	 * The delays are indicated by characters above 0200.
757 	 * In raw mode there are no delays and the
758 	 * transmission path is 8 bits wide.
759 	 */
760 	colp = &tp->t_col;
761 	ctype = partab[c];
762 	c = 0;
763 	switch (ctype&077) {
764 
765 	/* ordinary */
766 	case 0:
767 		(*colp)++;
768 
769 	/* non-printing */
770 	case 1:
771 		break;
772 
773 	/* backspace */
774 	case 2:
775 		if (*colp)
776 			(*colp)--;
777 		break;
778 
779 	/* newline */
780 	case 3:
781 		ctype = (tp->t_flags >> 8) & 03;
782 		if(ctype == 1) { /* tty 37 */
783 			if (*colp)
784 				c = max(((unsigned)*colp>>4) + 3, (unsigned)6);
785 		} else
786 		if(ctype == 2) { /* vt05 */
787 			c = 6;
788 		}
789 		*colp = 0;
790 		break;
791 
792 	/* tab */
793 	case 4:
794 		ctype = (tp->t_flags >> 10) & 03;
795 		if(ctype == 1) { /* tty 37 */
796 			c = 1 - (*colp | ~07);
797 			if(c < 5)
798 				c = 0;
799 		}
800 		*colp |= 07;
801 		(*colp)++;
802 		break;
803 
804 	/* vertical motion */
805 	case 5:
806 		if(tp->t_flags & VTDELAY) /* tty 37 */
807 			c = 0177;
808 		break;
809 
810 	/* carriage return */
811 	case 6:
812 		ctype = (tp->t_flags >> 12) & 03;
813 		if(ctype == 1) { /* tn 300 */
814 			c = 5;
815 		} else if(ctype == 2) { /* ti 700 */
816 			c = 10;
817 		} else if(ctype == 3) { /* concept 100 */
818 			int i;
819 			if ((i = *colp) >= 0)
820 				for (; i<9; i++)
821 					(void) putc(0177, &tp->t_outq);
822 		}
823 		*colp = 0;
824 	}
825 	if(c)
826 		(void) putc(c|0200, &tp->t_outq);
827 }
828 
829 /*
830  * Restart typewriter output following a delay
831  * timeout.
832  * The name of the routine is passed to the timeout
833  * subroutine and it is called during a clock interrupt.
834  */
835 ttrstrt(tp)
836 register struct tty *tp;
837 {
838 
839 	tp->t_state &= ~TIMEOUT;
840 	ttstart(tp);
841 }
842 
843 /*
844  * Start output on the typewriter. It is used from the top half
845  * after some characters have been put on the output queue,
846  * from the interrupt routine to transmit the next
847  * character, and after a timeout has finished.
848  */
849 ttstart(tp)
850 register struct tty *tp;
851 {
852 	register s;
853 
854 	s = spl5();
855 	if((tp->t_state&(TIMEOUT|TTSTOP|BUSY)) == 0)
856 		(*tp->t_oproc)(tp);
857 	splx(s);
858 }
859 
860 /*
861  * Called from device's read routine after it has
862  * calculated the tty-structure given as argument.
863  */
864 ttread(tp)
865 register struct tty *tp;
866 {
867 register s;
868 
869 	if ((tp->t_state&CARR_ON)==0)
870 		return(-1);
871 	s = spl5();
872 	if (tp->t_canq.c_cc==0)
873 		while (canon(tp)<0)
874 			if (tp->t_chan==NULL) {
875 				sleep((caddr_t)&tp->t_rawq, TTIPRI);
876 			} else {
877 				splx(s);
878 				return(0);
879 			}
880 	splx(s);
881 	while (tp->t_canq.c_cc && passc(getc(&tp->t_canq))>=0)
882 			;
883 	return(tp->t_rawq.c_cc+tp->t_canq.c_cc);
884 }
885 
886 /*
887  * Called from the device's write routine after it has
888  * calculated the tty-structure given as argument.
889  */
890 caddr_t
891 ttwrite(tp)
892 register struct tty *tp;
893 {
894 	/*
895 	 * THE POSITIONING OF CP, CC, AND CE ARE CRITICAL
896 	 * AND MUST NOT BE CHANGED WITHOUT PATCHING
897 	 * THE 'ASM' INLINES BELOW.  WATCH OUT.
898 	 */
899 	register char *cp;
900 	register int cc, ce;
901 	register i;
902 	char obuf[OBUFSIZ];
903 
904 	if ((tp->t_state&CARR_ON)==0)
905 		return(NULL);
906 	while (u.u_count) {
907 		cc = MIN(u.u_count, OBUFSIZ);
908 		cp = obuf;
909 		iomove(cp, (unsigned)cc, B_WRITE);
910 		if (u.u_error)
911 			break;
912 		(void) spl5();
913 		while (tp->t_outq.c_cc > TTHIWAT) {
914 			ttstart(tp);
915 			tp->t_state |= ASLEEP;
916 			if (tp->t_chan) {
917 				u.u_base -= cc;
918 				u.u_offset -= cc;
919 				u.u_count += cc;
920 				(void) spl0();
921 				return((caddr_t)&tp->t_outq);
922 			}
923 			sleep((caddr_t)&tp->t_outq, TTOPRI);
924 		}
925 		(void) spl0();
926 		if (tp->t_flags&LCASE) {
927 			while (cc--)
928 				ttyoutput(*cp++,tp);
929 			continue;
930 		}
931 		while (cc) {
932 			if (tp->t_flags&RAW)
933 				ce=cc;
934 			else {
935 #ifdef VAX
936 				asm("	scanc	r9,(r10),_partab,$077");
937 				asm("	subl3	r0,r9,r8");
938 #else
939 				ce=0;
940 				while(((partab[*(cp+ce)]&077)==0)&&(ce<cc))
941 					ce++;
942 #endif
943 				if (ce==0) {
944 					ttyoutput(*cp++,tp);
945 					cc--;
946 					goto check;
947 				}
948 			}
949 			i=b_to_q(cp,ce,&tp->t_outq);
950 			ce-=i;
951 			tk_nout+=ce;
952 			tp->t_col+=ce;
953 			cp+=ce;
954 			cc-=ce;
955 check:
956 			if (tp->t_outq.c_cc > TTHIWAT) {
957 				(void) spl5();
958 				while (tp->t_outq.c_cc > TTHIWAT) {
959 					ttstart(tp);
960 					tp->t_state |= ASLEEP;
961 					sleep((caddr_t)&tp->t_outq, TTOPRI);
962 				}
963 				(void) spl0();
964 			}
965 		}
966 	}
967 	ttstart(tp);
968 	return(NULL);
969 }
970