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