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