xref: /csrg-svn/sys/kern/tty.c (revision 887)
1 /*	tty.c	3.15	09/16/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 	register c;
228 	int temp;
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, FREAD|FWRITE);
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 		if (copyin(addr, (caddr_t)&tp->t_pgrp, sizeof (tp->t_pgrp)))
407 			u.u_error = EFAULT;
408 		break;
409 
410 	case TIOCGPGRP:
411 		if (copyout((caddr_t)&tp->t_pgrp, addr, sizeof(tp->t_pgrp)))
412 			u.u_error = EFAULT;
413 		break;
414 
415 	/*
416 	 * Modify local mode word.
417 	 */
418 	case TIOCLBIS:
419 		if (copyin(addr, (caddr_t)&temp, sizeof (tp->t_local)))
420 			u.u_error = EFAULT;
421 		else
422 			tp->t_local |= temp;
423 		break;
424 
425 	case TIOCLBIC:
426 		if (copyin(addr, (caddr_t)&temp, sizeof (tp->t_local)))
427 			u.u_error = EFAULT;
428 		else
429 			tp->t_local &= ~temp;
430 		break;
431 
432 	case TIOCLSET:
433 		if (copyin(addr, (caddr_t)&temp, sizeof (tp->t_local)))
434 			u.u_error = EFAULT;
435 		else
436 			tp->t_local = temp;
437 		break;
438 
439 	case TIOCLGET:
440 		if (copyout((caddr_t)&tp->t_local, addr, sizeof(tp->t_local)))
441 			u.u_error = EFAULT;
442 		break;
443 
444 	case TIOCOUTQ:
445 		if (copyout((caddr_t)&tp->t_outq.c_cc, addr, sizeof(tp->t_outq.c_cc)))
446 			u.u_error = EFAULT;
447 		break;
448 
449 	case TIOCSTI:
450 		c = fubyte(addr);
451 		if (u.u_uid && u.u_ttyp != tp || c < 0)
452 			u.u_error = EFAULT;
453 		else
454 			(*linesw[tp->t_line].l_rint)(c, tp);
455 		break;
456 /* end of locals */
457 
458 	default:
459 		return(0);
460 	}
461 	return(1);
462 }
463 
464 /*
465  * Wait for output to drain, then flush input waiting.
466  */
467 wflushtty(tp)
468 register struct tty *tp;
469 {
470 
471 	(void) spl5();
472 	while (tp->t_outq.c_cc && tp->t_state&CARR_ON) {
473 		(*tp->t_oproc)(tp);
474 		tp->t_state |= ASLEEP;
475 		sleep((caddr_t)&tp->t_outq, TTOPRI);
476 	}
477 	flushtty(tp, FREAD|FWRITE);
478 	(void) spl0();
479 }
480 
481 /*
482  * flush all TTY queues
483  */
484 flushtty(tp, rw)
485 register struct tty *tp;
486 {
487 	register s;
488 
489 	if (tp->t_line == NETLDISC)
490 		return;
491 	s = spl6();
492 	if (rw & FREAD) {
493 		while (getc(&tp->t_canq) >= 0)
494 			;
495 		wakeup((caddr_t)&tp->t_rawq);
496 	}
497 	if (rw & FWRITE) {
498 		wakeup((caddr_t)&tp->t_outq);
499 		tp->t_state &= ~TTSTOP;
500 		(*cdevsw[major(tp->t_dev)].d_stop)(tp);
501 		while (getc(&tp->t_outq) >= 0)
502 			;
503 	}
504 	if (rw & FREAD) {
505 		while (getc(&tp->t_rawq) >= 0)
506 			;
507 		tp->t_delct = 0;
508 		tp->t_rocount = 0;		/* local */
509 		tp->t_rocol = 0;
510 		tp->t_lstate = 0;
511 	}
512 	splx(s);
513 }
514 
515 
516 
517 /*
518  * transfer raw input list to canonical list,
519  * doing erase-kill processing and handling escapes.
520  * It waits until a full line has been typed in cooked mode,
521  * or until any character has been typed in raw mode.
522  */
523 canon(tp)
524 register struct tty *tp;
525 {
526 	register char *bp;
527 	char *bp1;
528 	register int c;
529 	int mc;
530 	int s;
531 
532 	if ((tp->t_flags&(RAW|CBREAK))==0 && tp->t_delct==0
533 	    || (tp->t_flags&(RAW|CBREAK))!=0 && tp->t_rawq.c_cc==0) {
534 		return(-1);
535 	}
536 	s = spl0();
537 loop:
538 	bp = &canonb[2];
539 	while ((c=getc(&tp->t_rawq)) >= 0) {
540 		if ((tp->t_flags&(RAW|CBREAK))==0) {
541 			if (c==0377) {
542 				tp->t_delct--;
543 				break;
544 			}
545 			if (bp[-1]!='\\') {
546 				if (c==tp->t_erase) {
547 					if (bp > &canonb[2])
548 						bp--;
549 					continue;
550 				}
551 				if (c==tp->t_kill)
552 					goto loop;
553 				if (c==tun.t_eofc)
554 					continue;
555 			} else {
556 				mc = maptab[c];
557 				if (c==tp->t_erase || c==tp->t_kill)
558 					mc = c;
559 				if (mc && (mc==c || (tp->t_flags&LCASE))) {
560 					if (bp[-2] != '\\')
561 						c = mc;
562 					bp--;
563 				}
564 			}
565 		}
566 		*bp++ = c;
567 		if (bp>=canonb+CANBSIZ)
568 			break;
569 	}
570 	bp1 = &canonb[2];
571 	(void) b_to_q(bp1, bp-bp1, &tp->t_canq);
572 
573 	if (tp->t_state&TBLOCK && tp->t_rawq.c_cc < TTYHOG/5) {
574 		if (putc(tun.t_startc, &tp->t_outq)==0) {
575 			tp->t_state &= ~TBLOCK;
576 			ttstart(tp);
577 		}
578 		tp->t_char = 0;
579 	}
580 
581 	splx(s);
582 	return(0);
583 }
584 
585 
586 /*
587  * block transfer input handler.
588  */
589 ttyrend(tp, pb, pe)
590 register struct tty *tp;
591 register char *pb, *pe;
592 {
593 	int	tandem;
594 
595 	tandem = tp->t_flags&TANDEM;
596 	if (tp->t_flags&RAW) {
597 		(void) b_to_q(pb, pe-pb, &tp->t_rawq);
598 		if (tp->t_chan)
599 			(void) sdata(tp->t_chan); else
600 			wakeup((caddr_t)&tp->t_rawq);
601 	} else {
602 		tp->t_flags &= ~TANDEM;
603 		while (pb < pe)
604 			ttyinput(*pb++, tp);
605 		tp->t_flags |= tandem;
606 	}
607 	if (tandem)
608 		ttyblock(tp);
609 }
610 
611 /*
612  * Place a character on raw TTY input queue, putting in delimiters
613  * and waking up top half as needed.
614  * Also echo if required.
615  * The arguments are the character and the appropriate
616  * tty structure.
617  */
618 ttyinput(c, tp)
619 register c;
620 register struct tty *tp;
621 {
622 	register int t_flags;
623 	register struct chan *cp;
624 
625 	tk_nin += 1;
626 	c &= 0377;
627 	t_flags = tp->t_flags;
628 	if (t_flags&TANDEM)
629 		ttyblock(tp);
630 	if ((t_flags&RAW)==0) {
631 		c &= 0177;
632 		if (tp->t_state&TTSTOP) {
633 			if (c==tun.t_startc) {
634 				tp->t_state &= ~TTSTOP;
635 				ttstart(tp);
636 				return;
637 			}
638 			if (c==tun.t_stopc)
639 				return;
640 			tp->t_state &= ~TTSTOP;
641 			ttstart(tp);
642 		} else {
643 			if (c==tun.t_stopc) {
644 				tp->t_state |= TTSTOP;
645 				(*cdevsw[major(tp->t_dev)].d_stop)(tp);
646 				return;
647 			}
648 			if (c==tun.t_startc)
649 				return;
650 		}
651 		if (c==tun.t_quitc || c==tun.t_intrc) {
652 			flushtty(tp, FREAD|FWRITE);
653 			c = (c==tun.t_intrc) ? SIGINT:SIGQUIT;
654 			if (tp->t_chan)
655 				scontrol(tp->t_chan, M_SIG, c);
656 			else
657 				gsignal(tp->t_pgrp, c);
658 			return;
659 		}
660 		if (c=='\r' && t_flags&CRMOD)
661 			c = '\n';
662 	}
663 	if (tp->t_rawq.c_cc>TTYHOG) {
664 		flushtty(tp, FREAD|FWRITE);
665 		return;
666 	}
667 	if (t_flags&LCASE && c>='A' && c<='Z')
668 		c += 'a'-'A';
669 	(void) putc(c, &tp->t_rawq);
670 	if (t_flags&(RAW|CBREAK)||(c=='\n'||c==tun.t_eofc||c==tun.t_brkc)) {
671 		if ((t_flags&(RAW|CBREAK))==0 && putc(0377, &tp->t_rawq)==0)
672 			tp->t_delct++;
673 		if ((cp=tp->t_chan)!=NULL)
674 			(void) sdata(cp); else
675 			wakeup((caddr_t)&tp->t_rawq);
676 	}
677 	if (t_flags&ECHO) {
678 		ttyoutput(c, tp);
679 		if (c==tp->t_kill && (t_flags&(RAW|CBREAK))==0)
680 			ttyoutput('\n', tp);
681 		ttstart(tp);
682 	}
683 }
684 
685 
686 /*
687  * Send stop character on input overflow.
688  */
689 ttyblock(tp)
690 register struct tty *tp;
691 {
692 	register x;
693 	x = q1.c_cc + q2.c_cc;
694 	if (q1.c_cc > TTYHOG) {
695 		flushtty(tp, FREAD|FWRITE);
696 		tp->t_state &= ~TBLOCK;
697 	}
698 	if (x >= TTYHOG/2) {
699 		if (putc(tun.t_stopc, &tp->t_outq)==0) {
700 			tp->t_state |= TBLOCK;
701 			tp->t_char++;
702 			ttstart(tp);
703 		}
704 	}
705 }
706 
707 /*
708  * put character on TTY output queue, adding delays,
709  * expanding tabs, and handling the CR/NL bit.
710  * It is called both from the top half for output, and from
711  * interrupt level for echoing.
712  * The arguments are the character and the tty structure.
713  */
714 ttyoutput(c, tp)
715 register c;
716 register struct tty *tp;
717 {
718 	register char *colp;
719 	register ctype;
720 
721 	/*
722 	 * Ignore EOT in normal mode to avoid hanging up
723 	 * certain terminals.
724 	 * In raw mode dump the char unchanged.
725 	 */
726 	if ((tp->t_flags&RAW)==0) {
727 		c &= 0177;
728 		if ((tp->t_flags&CBREAK)==0 && c==CEOT)
729 			return;
730 	} else {
731 		tk_nout++;
732 		(void) putc(c, &tp->t_outq);
733 		return;
734 	}
735 
736 	/*
737 	 * Turn tabs to spaces as required
738 	 */
739 	if (c=='\t' && (tp->t_flags&TBDELAY)==XTABS) {
740 		c = 8 - (tp->t_col & 7);
741 		(void) b_to_q("        ", c, &tp->t_outq);
742 		tp->t_col += c;
743 		tk_nout += c;
744 		return;
745 	}
746 	tk_nout++;
747 	/*
748 	 * for upper-case-only terminals,
749 	 * generate escapes.
750 	 */
751 	if (tp->t_flags&LCASE) {
752 		colp = "({)}!|^~'`";
753 		while(*colp++)
754 			if(c == *colp++) {
755 				ttyoutput('\\', tp);
756 				c = colp[-2];
757 				break;
758 			}
759 		if ('a'<=c && c<='z')
760 			c += 'A' - 'a';
761 	}
762 	/*
763 	 * turn <nl> to <cr><lf> if desired.
764 	 */
765 	if (c=='\n' && tp->t_flags&CRMOD)
766 		ttyoutput('\r', tp);
767 	(void) putc(c, &tp->t_outq);
768 	/*
769 	 * Calculate delays.
770 	 * The numbers here represent clock ticks
771 	 * and are not necessarily optimal for all terminals.
772 	 * The delays are indicated by characters above 0200.
773 	 * In raw mode there are no delays and the
774 	 * transmission path is 8 bits wide.
775 	 */
776 	colp = &tp->t_col;
777 	ctype = partab[c];
778 	c = 0;
779 	switch (ctype&077) {
780 
781 	/* ordinary */
782 	case 0:
783 		(*colp)++;
784 
785 	/* non-printing */
786 	case 1:
787 		break;
788 
789 	/* backspace */
790 	case 2:
791 		if (*colp)
792 			(*colp)--;
793 		break;
794 
795 	/* newline */
796 	case 3:
797 		ctype = (tp->t_flags >> 8) & 03;
798 		if(ctype == 1) { /* tty 37 */
799 			if (*colp)
800 				c = max(((unsigned)*colp>>4) + 3, (unsigned)6);
801 		} else
802 		if(ctype == 2) { /* vt05 */
803 			c = 6;
804 		}
805 		*colp = 0;
806 		break;
807 
808 	/* tab */
809 	case 4:
810 		ctype = (tp->t_flags >> 10) & 03;
811 		if(ctype == 1) { /* tty 37 */
812 			c = 1 - (*colp | ~07);
813 			if(c < 5)
814 				c = 0;
815 		}
816 		*colp |= 07;
817 		(*colp)++;
818 		break;
819 
820 	/* vertical motion */
821 	case 5:
822 		if(tp->t_flags & VTDELAY) /* tty 37 */
823 			c = 0177;
824 		break;
825 
826 	/* carriage return */
827 	case 6:
828 		ctype = (tp->t_flags >> 12) & 03;
829 		if(ctype == 1) { /* tn 300 */
830 			c = 5;
831 		} else if(ctype == 2) { /* ti 700 */
832 			c = 10;
833 		} else if(ctype == 3) { /* concept 100 */
834 			int i;
835 			if ((i = *colp) >= 0)
836 				for (; i<9; i++)
837 					(void) putc(0177, &tp->t_outq);
838 		}
839 		*colp = 0;
840 	}
841 	if(c)
842 		(void) putc(c|0200, &tp->t_outq);
843 }
844 
845 /*
846  * Restart typewriter output following a delay
847  * timeout.
848  * The name of the routine is passed to the timeout
849  * subroutine and it is called during a clock interrupt.
850  */
851 ttrstrt(tp)
852 register struct tty *tp;
853 {
854 
855 	tp->t_state &= ~TIMEOUT;
856 	ttstart(tp);
857 }
858 
859 /*
860  * Start output on the typewriter. It is used from the top half
861  * after some characters have been put on the output queue,
862  * from the interrupt routine to transmit the next
863  * character, and after a timeout has finished.
864  */
865 ttstart(tp)
866 register struct tty *tp;
867 {
868 	register s;
869 
870 	s = spl5();
871 	if((tp->t_state&(TIMEOUT|TTSTOP|BUSY)) == 0)
872 		(*tp->t_oproc)(tp);
873 	splx(s);
874 }
875 
876 /*
877  * Called from device's read routine after it has
878  * calculated the tty-structure given as argument.
879  */
880 ttread(tp)
881 register struct tty *tp;
882 {
883 register s;
884 
885 	if ((tp->t_state&CARR_ON)==0)
886 		return(-1);
887 	s = spl5();
888 	if (tp->t_canq.c_cc==0)
889 		while (canon(tp)<0)
890 			if (tp->t_chan==NULL) {
891 				sleep((caddr_t)&tp->t_rawq, TTIPRI);
892 			} else {
893 				splx(s);
894 				return(0);
895 			}
896 	splx(s);
897 	while (tp->t_canq.c_cc && passc(getc(&tp->t_canq))>=0)
898 			;
899 	return(tp->t_rawq.c_cc+tp->t_canq.c_cc);
900 }
901 
902 /*
903  * Called from the device's write routine after it has
904  * calculated the tty-structure given as argument.
905  */
906 caddr_t
907 ttwrite(tp)
908 register struct tty *tp;
909 {
910 	/*
911 	 * THE POSITIONING OF CP, CC, AND CE ARE CRITICAL
912 	 * AND MUST NOT BE CHANGED WITHOUT PATCHING
913 	 * THE 'ASM' INLINES BELOW.  WATCH OUT.
914 	 */
915 	register char *cp;
916 	register int cc, ce;
917 	register i;
918 	char obuf[OBUFSIZ];
919 
920 	if ((tp->t_state&CARR_ON)==0)
921 		return(NULL);
922 	while (u.u_count) {
923 		cc = MIN(u.u_count, OBUFSIZ);
924 		cp = obuf;
925 		iomove(cp, (unsigned)cc, B_WRITE);
926 		if (u.u_error)
927 			break;
928 		(void) spl5();
929 		while (tp->t_outq.c_cc > TTHIWAT) {
930 			ttstart(tp);
931 			tp->t_state |= ASLEEP;
932 			if (tp->t_chan) {
933 				u.u_base -= cc;
934 				u.u_offset -= cc;
935 				u.u_count += cc;
936 				(void) spl0();
937 				return((caddr_t)&tp->t_outq);
938 			}
939 			sleep((caddr_t)&tp->t_outq, TTOPRI);
940 		}
941 		(void) spl0();
942 		if (tp->t_flags&LCASE) {
943 			while (cc--)
944 				ttyoutput(*cp++,tp);
945 			continue;
946 		}
947 		while (cc) {
948 			if (tp->t_flags&RAW)
949 				ce=cc;
950 			else {
951 #ifdef VAX
952 				asm("	scanc	r9,(r10),_partab,$077");
953 				asm("	subl3	r0,r9,r8");
954 #else
955 				ce=0;
956 				while(((partab[*(cp+ce)]&077)==0)&&(ce<cc))
957 					ce++;
958 #endif
959 				if (ce==0) {
960 					ttyoutput(*cp++,tp);
961 					cc--;
962 					goto check;
963 				}
964 			}
965 			i=b_to_q(cp,ce,&tp->t_outq);
966 			ce-=i;
967 			tk_nout+=ce;
968 			tp->t_col+=ce;
969 			cp+=ce;
970 			cc-=ce;
971 check:
972 			if (tp->t_outq.c_cc > TTHIWAT) {
973 				(void) spl5();
974 				while (tp->t_outq.c_cc > TTHIWAT) {
975 					ttstart(tp);
976 					tp->t_state |= ASLEEP;
977 					sleep((caddr_t)&tp->t_outq, TTOPRI);
978 				}
979 				(void) spl0();
980 			}
981 		}
982 	}
983 	ttstart(tp);
984 	return(NULL);
985 }
986