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