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