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