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