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