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