xref: /csrg-svn/sys/kern/tty.c (revision 39)
1*39Sbill /*	tty.c	3.1	10/14/12	*/
2*39Sbill 
3*39Sbill /*
4*39Sbill  * general TTY subroutines
5*39Sbill  */
6*39Sbill #include "../h/param.h"
7*39Sbill #include "../h/systm.h"
8*39Sbill #include "../h/dir.h"
9*39Sbill #include "../h/user.h"
10*39Sbill #include "../h/tty.h"
11*39Sbill #include "../h/proc.h"
12*39Sbill #include "../h/mx.h"
13*39Sbill #include "../h/inode.h"
14*39Sbill #include "../h/file.h"
15*39Sbill #include "../h/reg.h"
16*39Sbill #include "../h/conf.h"
17*39Sbill #include "../h/buf.h"
18*39Sbill 
19*39Sbill char	partab[];
20*39Sbill 
21*39Sbill 
22*39Sbill /*
23*39Sbill  * Input mapping table-- if an entry is non-zero, when the
24*39Sbill  * corresponding character is typed preceded by "\" the escape
25*39Sbill  * sequence is replaced by the table value.  Mostly used for
26*39Sbill  * upper-case only terminals.
27*39Sbill  */
28*39Sbill 
29*39Sbill char	maptab[] ={
30*39Sbill 	000,000,000,000,000,000,000,000,
31*39Sbill 	000,000,000,000,000,000,000,000,
32*39Sbill 	000,000,000,000,000,000,000,000,
33*39Sbill 	000,000,000,000,000,000,000,000,
34*39Sbill 	000,'|',000,000,000,000,000,'`',
35*39Sbill 	'{','}',000,000,000,000,000,000,
36*39Sbill 	000,000,000,000,000,000,000,000,
37*39Sbill 	000,000,000,000,000,000,000,000,
38*39Sbill 	000,000,000,000,000,000,000,000,
39*39Sbill 	000,000,000,000,000,000,000,000,
40*39Sbill 	000,000,000,000,000,000,000,000,
41*39Sbill 	000,000,000,000,000,000,'~',000,
42*39Sbill 	000,'A','B','C','D','E','F','G',
43*39Sbill 	'H','I','J','K','L','M','N','O',
44*39Sbill 	'P','Q','R','S','T','U','V','W',
45*39Sbill 	'X','Y','Z',000,000,000,000,000,
46*39Sbill };
47*39Sbill 
48*39Sbill 
49*39Sbill /*
50*39Sbill  * shorthand
51*39Sbill  */
52*39Sbill #define	q1	tp->t_rawq
53*39Sbill #define	q2	tp->t_canq
54*39Sbill #define	q3	tp->t_outq
55*39Sbill #define	q4	tp->t_un.t_ctlq
56*39Sbill 
57*39Sbill #define	OBUFSIZ	100
58*39Sbill 
59*39Sbill /*
60*39Sbill  * routine called on first teletype open.
61*39Sbill  * establishes a process group for distribution
62*39Sbill  * of quits and interrupts from the tty.
63*39Sbill  */
64*39Sbill ttyopen(dev, tp)
65*39Sbill dev_t dev;
66*39Sbill register struct tty *tp;
67*39Sbill {
68*39Sbill 	register struct proc *pp;
69*39Sbill 
70*39Sbill 	pp = u.u_procp;
71*39Sbill 	tp->t_dev = dev;
72*39Sbill 	if(pp->p_pgrp == 0) {
73*39Sbill 		u.u_ttyp = tp;
74*39Sbill 		u.u_ttyd = dev;
75*39Sbill 		if (tp->t_pgrp==0)
76*39Sbill 			tp->t_pgrp = pp->p_pid;
77*39Sbill 		pp->p_pgrp = tp->t_pgrp;
78*39Sbill 	}
79*39Sbill 	tp->t_state &= ~WOPEN;
80*39Sbill 	tp->t_state |= ISOPEN;
81*39Sbill }
82*39Sbill 
83*39Sbill 
84*39Sbill /*
85*39Sbill  * set default control characters.
86*39Sbill  */
87*39Sbill ttychars(tp)
88*39Sbill register struct tty *tp;
89*39Sbill {
90*39Sbill 	tun.t_intrc = CINTR;
91*39Sbill 	tun.t_quitc = CQUIT;
92*39Sbill 	tun.t_startc = CSTART;
93*39Sbill 	tun.t_stopc = CSTOP;
94*39Sbill 	tun.t_eofc = CEOT;
95*39Sbill 	tun.t_brkc = CBRK;
96*39Sbill 	tp->t_erase = CERASE;
97*39Sbill 	tp->t_kill = CKILL;
98*39Sbill }
99*39Sbill 
100*39Sbill /*
101*39Sbill  * clean tp on last close
102*39Sbill  */
103*39Sbill ttyclose(tp)
104*39Sbill register struct tty *tp;
105*39Sbill {
106*39Sbill 
107*39Sbill 	tp->t_pgrp = 0;
108*39Sbill 	wflushtty(tp);
109*39Sbill 	tp->t_state = 0;
110*39Sbill }
111*39Sbill 
112*39Sbill /*
113*39Sbill  * stty/gtty writearound
114*39Sbill  */
115*39Sbill stty()
116*39Sbill {
117*39Sbill 	u.u_arg[2] = u.u_arg[1];
118*39Sbill 	u.u_arg[1] = TIOCSETP;
119*39Sbill 	ioctl();
120*39Sbill }
121*39Sbill 
122*39Sbill gtty()
123*39Sbill {
124*39Sbill 	u.u_arg[2] = u.u_arg[1];
125*39Sbill 	u.u_arg[1] = TIOCGETP;
126*39Sbill 	ioctl();
127*39Sbill }
128*39Sbill 
129*39Sbill /*
130*39Sbill  * ioctl system call
131*39Sbill  * Check legality, execute common code, and switch out to individual
132*39Sbill  * device routine.
133*39Sbill  */
134*39Sbill ioctl()
135*39Sbill {
136*39Sbill 	register struct file *fp;
137*39Sbill 	register struct inode *ip;
138*39Sbill 	register struct a {
139*39Sbill 		int	fdes;
140*39Sbill 		int	cmd;
141*39Sbill 		caddr_t	cmarg;
142*39Sbill 	} *uap;
143*39Sbill 	register dev_t dev;
144*39Sbill 	register fmt;
145*39Sbill 
146*39Sbill 	uap = (struct a *)u.u_ap;
147*39Sbill 	if ((fp = getf(uap->fdes)) == NULL)
148*39Sbill 		return;
149*39Sbill 	if (uap->cmd==FIOCLEX) {
150*39Sbill 		u.u_pofile[uap->fdes] |= EXCLOSE;
151*39Sbill 		return;
152*39Sbill 	}
153*39Sbill 	if (uap->cmd==FIONCLEX) {
154*39Sbill 		u.u_pofile[uap->fdes] &= ~EXCLOSE;
155*39Sbill 		return;
156*39Sbill 	}
157*39Sbill 	ip = fp->f_inode;
158*39Sbill 	fmt = ip->i_mode & IFMT;
159*39Sbill 	if (fmt != IFCHR && fmt != IFMPC) {
160*39Sbill 		u.u_error = ENOTTY;
161*39Sbill 		return;
162*39Sbill 	}
163*39Sbill 	dev = ip->i_un.i_rdev;
164*39Sbill 	u.u_r.r_val1 = 0;
165*39Sbill 	(*cdevsw[major(dev)].d_ioctl)(dev, uap->cmd, uap->cmarg, fp->f_flag);
166*39Sbill }
167*39Sbill 
168*39Sbill /*
169*39Sbill  * Common code for several tty ioctl commands
170*39Sbill  */
171*39Sbill ttioccomm(com, tp, addr, dev)
172*39Sbill register struct tty *tp;
173*39Sbill caddr_t addr;
174*39Sbill {
175*39Sbill 	unsigned t;
176*39Sbill 	struct ttiocb iocb;
177*39Sbill 	extern int nldisp;
178*39Sbill 
179*39Sbill 	switch(com) {
180*39Sbill 
181*39Sbill 	/*
182*39Sbill 	 * get discipline number
183*39Sbill 	 */
184*39Sbill 	case TIOCGETD:
185*39Sbill 		t = tp->t_line;
186*39Sbill 		if (copyout((caddr_t)&t, addr, sizeof(t)))
187*39Sbill 			u.u_error = EFAULT;
188*39Sbill 		break;
189*39Sbill 
190*39Sbill 	/*
191*39Sbill 	 * set line discipline
192*39Sbill 	 */
193*39Sbill 	case TIOCSETD:
194*39Sbill 		if (copyin(addr, (caddr_t)&t, sizeof(t))) {
195*39Sbill 			u.u_error = EFAULT;
196*39Sbill 			break;
197*39Sbill 		}
198*39Sbill 		if (t >= nldisp) {
199*39Sbill 			u.u_error = ENXIO;
200*39Sbill 			break;
201*39Sbill 		}
202*39Sbill 		if (tp->t_line)
203*39Sbill 			(*linesw[tp->t_line].l_close)(tp);
204*39Sbill 		if (t)
205*39Sbill 			(*linesw[t].l_open)(dev, tp, addr);
206*39Sbill 		if (u.u_error==0)
207*39Sbill 			tp->t_line = t;
208*39Sbill 		break;
209*39Sbill 
210*39Sbill 	/*
211*39Sbill 	 * prevent more opens on channel
212*39Sbill 	 */
213*39Sbill 	case TIOCEXCL:
214*39Sbill 		tp->t_state |= XCLUDE;
215*39Sbill 		break;
216*39Sbill 
217*39Sbill 	case TIOCNXCL:
218*39Sbill 		tp->t_state &= ~XCLUDE;
219*39Sbill 		break;
220*39Sbill 
221*39Sbill 	/*
222*39Sbill 	 * Set new parameters
223*39Sbill 	 */
224*39Sbill 	case TIOCSETP:
225*39Sbill 		wflushtty(tp);
226*39Sbill 	case TIOCSETN:
227*39Sbill 		if (copyin(addr, (caddr_t)&iocb, sizeof(iocb))) {
228*39Sbill 			u.u_error = EFAULT;
229*39Sbill 			return(1);
230*39Sbill 		}
231*39Sbill 		VOID spl5();
232*39Sbill 		while (canon(tp)>=0)
233*39Sbill 			;
234*39Sbill 		if ((tp->t_state&SPEEDS)==0) {
235*39Sbill 			tp->t_ispeed = iocb.ioc_ispeed;
236*39Sbill 			tp->t_ospeed = iocb.ioc_ospeed;
237*39Sbill 		}
238*39Sbill 		tp->t_erase = iocb.ioc_erase;
239*39Sbill 		tp->t_kill = iocb.ioc_kill;
240*39Sbill 		tp->t_flags = iocb.ioc_flags;
241*39Sbill 		VOID spl0();
242*39Sbill 		break;
243*39Sbill 
244*39Sbill 	/*
245*39Sbill 	 * send current parameters to user
246*39Sbill 	 */
247*39Sbill 	case TIOCGETP:
248*39Sbill 		iocb.ioc_ispeed = tp->t_ispeed;
249*39Sbill 		iocb.ioc_ospeed = tp->t_ospeed;
250*39Sbill 		iocb.ioc_erase = tp->t_erase;
251*39Sbill 		iocb.ioc_kill = tp->t_kill;
252*39Sbill 		iocb.ioc_flags = tp->t_flags;
253*39Sbill 		if (copyout((caddr_t)&iocb, addr, sizeof(iocb)))
254*39Sbill 			u.u_error = EFAULT;
255*39Sbill 		break;
256*39Sbill 
257*39Sbill 	/*
258*39Sbill 	 * Hang up line on last close
259*39Sbill 	 */
260*39Sbill 
261*39Sbill 	case TIOCHPCL:
262*39Sbill 		tp->t_state |= HUPCLS;
263*39Sbill 		break;
264*39Sbill 
265*39Sbill 	case TIOCFLUSH:
266*39Sbill 		flushtty(tp);
267*39Sbill 		break;
268*39Sbill 
269*39Sbill 	/*
270*39Sbill 	 * ioctl entries to line discipline
271*39Sbill 	 */
272*39Sbill 	case DIOCSETP:
273*39Sbill 	case DIOCGETP:
274*39Sbill 		(*linesw[tp->t_line].l_ioctl)(com, tp, addr);
275*39Sbill 		break;
276*39Sbill 
277*39Sbill 	/*
278*39Sbill 	 * set and fetch special characters
279*39Sbill 	 */
280*39Sbill 	case TIOCSETC:
281*39Sbill 		if (copyin(addr, (caddr_t)&tun, sizeof(struct tc)))
282*39Sbill 			u.u_error = EFAULT;
283*39Sbill 		break;
284*39Sbill 
285*39Sbill 	case TIOCGETC:
286*39Sbill 		if (copyout((caddr_t)&tun, addr, sizeof(struct tc)))
287*39Sbill 			u.u_error = EFAULT;
288*39Sbill 		break;
289*39Sbill 
290*39Sbill 	default:
291*39Sbill 		return(0);
292*39Sbill 	}
293*39Sbill 	return(1);
294*39Sbill }
295*39Sbill 
296*39Sbill /*
297*39Sbill  * Wait for output to drain, then flush input waiting.
298*39Sbill  */
299*39Sbill wflushtty(tp)
300*39Sbill register struct tty *tp;
301*39Sbill {
302*39Sbill 
303*39Sbill 	VOID spl5();
304*39Sbill 	while (tp->t_outq.c_cc && tp->t_state&CARR_ON) {
305*39Sbill 		(*tp->t_oproc)(tp);
306*39Sbill 		tp->t_state |= ASLEEP;
307*39Sbill 		sleep((caddr_t)&tp->t_outq, TTOPRI);
308*39Sbill 	}
309*39Sbill 	flushtty(tp);
310*39Sbill 	VOID spl0();
311*39Sbill }
312*39Sbill 
313*39Sbill /*
314*39Sbill  * flush all TTY queues
315*39Sbill  */
316*39Sbill flushtty(tp)
317*39Sbill register struct tty *tp;
318*39Sbill {
319*39Sbill 	register s;
320*39Sbill 
321*39Sbill 	while (getc(&tp->t_canq) >= 0)
322*39Sbill 		;
323*39Sbill 	wakeup((caddr_t)&tp->t_rawq);
324*39Sbill 	wakeup((caddr_t)&tp->t_outq);
325*39Sbill 	s = spl6();
326*39Sbill 	tp->t_state &= ~TTSTOP;
327*39Sbill 	(*cdevsw[major(tp->t_dev)].d_stop)(tp);
328*39Sbill 	while (getc(&tp->t_outq) >= 0)
329*39Sbill 		;
330*39Sbill 	while (getc(&tp->t_rawq) >= 0)
331*39Sbill 		;
332*39Sbill 	tp->t_delct = 0;
333*39Sbill 	splx(s);
334*39Sbill }
335*39Sbill 
336*39Sbill 
337*39Sbill 
338*39Sbill /*
339*39Sbill  * transfer raw input list to canonical list,
340*39Sbill  * doing erase-kill processing and handling escapes.
341*39Sbill  * It waits until a full line has been typed in cooked mode,
342*39Sbill  * or until any character has been typed in raw mode.
343*39Sbill  */
344*39Sbill canon(tp)
345*39Sbill register struct tty *tp;
346*39Sbill {
347*39Sbill 	register char *bp;
348*39Sbill 	char *bp1;
349*39Sbill 	register int c;
350*39Sbill 	int mc;
351*39Sbill 	int s;
352*39Sbill 
353*39Sbill 	if ((tp->t_flags&(RAW|CBREAK))==0 && tp->t_delct==0
354*39Sbill 	    || (tp->t_flags&(RAW|CBREAK))!=0 && tp->t_rawq.c_cc==0) {
355*39Sbill 		return(-1);
356*39Sbill 	}
357*39Sbill 	s = spl0();
358*39Sbill loop:
359*39Sbill 	bp = &canonb[2];
360*39Sbill 	while ((c=getc(&tp->t_rawq)) >= 0) {
361*39Sbill 		if ((tp->t_flags&(RAW|CBREAK))==0) {
362*39Sbill 			if (c==0377) {
363*39Sbill 				tp->t_delct--;
364*39Sbill 				break;
365*39Sbill 			}
366*39Sbill 			if (bp[-1]!='\\') {
367*39Sbill 				if (c==tp->t_erase) {
368*39Sbill 					if (bp > &canonb[2])
369*39Sbill 						bp--;
370*39Sbill 					continue;
371*39Sbill 				}
372*39Sbill 				if (c==tp->t_kill)
373*39Sbill 					goto loop;
374*39Sbill 				if (c==tun.t_eofc)
375*39Sbill 					continue;
376*39Sbill 			} else {
377*39Sbill 				mc = maptab[c];
378*39Sbill 				if (c==tp->t_erase || c==tp->t_kill)
379*39Sbill 					mc = c;
380*39Sbill 				if (mc && (mc==c || (tp->t_flags&LCASE))) {
381*39Sbill 					if (bp[-2] != '\\')
382*39Sbill 						c = mc;
383*39Sbill 					bp--;
384*39Sbill 				}
385*39Sbill 			}
386*39Sbill 		}
387*39Sbill 		*bp++ = c;
388*39Sbill 		if (bp>=canonb+CANBSIZ)
389*39Sbill 			break;
390*39Sbill 	}
391*39Sbill 	bp1 = &canonb[2];
392*39Sbill 	VOID b_to_q(bp1, bp-bp1, &tp->t_canq);
393*39Sbill 
394*39Sbill 	if (tp->t_state&TBLOCK && tp->t_rawq.c_cc < TTYHOG/5) {
395*39Sbill 		if (putc(tun.t_startc, &tp->t_outq)==0) {
396*39Sbill 			tp->t_state &= ~TBLOCK;
397*39Sbill 			ttstart(tp);
398*39Sbill 		}
399*39Sbill 		tp->t_char = 0;
400*39Sbill 	}
401*39Sbill 
402*39Sbill 	splx(s);
403*39Sbill 	return(0);
404*39Sbill }
405*39Sbill 
406*39Sbill 
407*39Sbill /*
408*39Sbill  * block transfer input handler.
409*39Sbill  */
410*39Sbill ttyrend(tp, pb, pe)
411*39Sbill register struct tty *tp;
412*39Sbill register char *pb, *pe;
413*39Sbill {
414*39Sbill 	int	tandem;
415*39Sbill 
416*39Sbill 	tandem = tp->t_flags&TANDEM;
417*39Sbill 	if (tp->t_flags&RAW) {
418*39Sbill 		VOID b_to_q(pb, pe-pb, &tp->t_rawq);
419*39Sbill 		if (tp->t_chan)
420*39Sbill 			VOID sdata(tp->t_chan); else
421*39Sbill 			wakeup((caddr_t)&tp->t_rawq);
422*39Sbill 	} else {
423*39Sbill 		tp->t_flags &= ~TANDEM;
424*39Sbill 		while (pb < pe)
425*39Sbill 			ttyinput(*pb++, tp);
426*39Sbill 		tp->t_flags |= tandem;
427*39Sbill 	}
428*39Sbill 	if (tandem)
429*39Sbill 		ttyblock(tp);
430*39Sbill }
431*39Sbill 
432*39Sbill /*
433*39Sbill  * Place a character on raw TTY input queue, putting in delimiters
434*39Sbill  * and waking up top half as needed.
435*39Sbill  * Also echo if required.
436*39Sbill  * The arguments are the character and the appropriate
437*39Sbill  * tty structure.
438*39Sbill  */
439*39Sbill ttyinput(c, tp)
440*39Sbill register c;
441*39Sbill register struct tty *tp;
442*39Sbill {
443*39Sbill 	register int t_flags;
444*39Sbill 	register struct chan *cp;
445*39Sbill 
446*39Sbill 	tk_nin += 1;
447*39Sbill 	c &= 0377;
448*39Sbill 	t_flags = tp->t_flags;
449*39Sbill 	if (t_flags&TANDEM)
450*39Sbill 		ttyblock(tp);
451*39Sbill 	if ((t_flags&RAW)==0) {
452*39Sbill 		c &= 0177;
453*39Sbill 		if (tp->t_state&TTSTOP) {
454*39Sbill 			if (c==tun.t_startc) {
455*39Sbill 				tp->t_state &= ~TTSTOP;
456*39Sbill 				ttstart(tp);
457*39Sbill 				return;
458*39Sbill 			}
459*39Sbill 			if (c==tun.t_stopc)
460*39Sbill 				return;
461*39Sbill 			tp->t_state &= ~TTSTOP;
462*39Sbill 			ttstart(tp);
463*39Sbill 		} else {
464*39Sbill 			if (c==tun.t_stopc) {
465*39Sbill 				tp->t_state |= TTSTOP;
466*39Sbill 				(*cdevsw[major(tp->t_dev)].d_stop)(tp);
467*39Sbill 				return;
468*39Sbill 			}
469*39Sbill 			if (c==tun.t_startc)
470*39Sbill 				return;
471*39Sbill 		}
472*39Sbill 		if (c==tun.t_quitc || c==tun.t_intrc) {
473*39Sbill 			flushtty(tp);
474*39Sbill 			c = (c==tun.t_intrc) ? SIGINT:SIGQUIT;
475*39Sbill 			if (tp->t_chan)
476*39Sbill 				scontrol(tp->t_chan, M_SIG, c);
477*39Sbill 			else
478*39Sbill 				signal(tp->t_pgrp, c);
479*39Sbill 			return;
480*39Sbill 		}
481*39Sbill 		if (c=='\r' && t_flags&CRMOD)
482*39Sbill 			c = '\n';
483*39Sbill 	}
484*39Sbill 	if (tp->t_rawq.c_cc>TTYHOG) {
485*39Sbill 		flushtty(tp);
486*39Sbill 		return;
487*39Sbill 	}
488*39Sbill 	if (t_flags&LCASE && c>='A' && c<='Z')
489*39Sbill 		c += 'a'-'A';
490*39Sbill 	VOID putc(c, &tp->t_rawq);
491*39Sbill 	if (t_flags&(RAW|CBREAK)||(c=='\n'||c==tun.t_eofc||c==tun.t_brkc)) {
492*39Sbill 		if ((t_flags&(RAW|CBREAK))==0 && putc(0377, &tp->t_rawq)==0)
493*39Sbill 			tp->t_delct++;
494*39Sbill 		if ((cp=tp->t_chan)!=NULL)
495*39Sbill 			VOID sdata(cp); else
496*39Sbill 			wakeup((caddr_t)&tp->t_rawq);
497*39Sbill 	}
498*39Sbill 	if (t_flags&ECHO) {
499*39Sbill 		ttyoutput(c, tp);
500*39Sbill 		if (c==tp->t_kill && (t_flags&(RAW|CBREAK))==0)
501*39Sbill 			ttyoutput('\n', tp);
502*39Sbill 		ttstart(tp);
503*39Sbill 	}
504*39Sbill }
505*39Sbill 
506*39Sbill 
507*39Sbill /*
508*39Sbill  * Send stop character on input overflow.
509*39Sbill  */
510*39Sbill ttyblock(tp)
511*39Sbill register struct tty *tp;
512*39Sbill {
513*39Sbill 	register x;
514*39Sbill 	x = q1.c_cc + q2.c_cc;
515*39Sbill 	if (q1.c_cc > TTYHOG) {
516*39Sbill 		flushtty(tp);
517*39Sbill 		tp->t_state &= ~TBLOCK;
518*39Sbill 	}
519*39Sbill 	if (x >= TTYHOG/2) {
520*39Sbill 		if (putc(tun.t_stopc, &tp->t_outq)==0) {
521*39Sbill 			tp->t_state |= TBLOCK;
522*39Sbill 			tp->t_char++;
523*39Sbill 			ttstart(tp);
524*39Sbill 		}
525*39Sbill 	}
526*39Sbill }
527*39Sbill 
528*39Sbill /*
529*39Sbill  * put character on TTY output queue, adding delays,
530*39Sbill  * expanding tabs, and handling the CR/NL bit.
531*39Sbill  * It is called both from the top half for output, and from
532*39Sbill  * interrupt level for echoing.
533*39Sbill  * The arguments are the character and the tty structure.
534*39Sbill  */
535*39Sbill ttyoutput(c, tp)
536*39Sbill register c;
537*39Sbill register struct tty *tp;
538*39Sbill {
539*39Sbill 	register char *colp;
540*39Sbill 	register ctype;
541*39Sbill 
542*39Sbill 	tk_nout++;
543*39Sbill 	/*
544*39Sbill 	 * Ignore EOT in normal mode to avoid hanging up
545*39Sbill 	 * certain terminals.
546*39Sbill 	 * In raw mode dump the char unchanged.
547*39Sbill 	 */
548*39Sbill 
549*39Sbill 	if ((tp->t_flags&RAW)==0) {
550*39Sbill 		c &= 0177;
551*39Sbill 		if ((tp->t_flags&CBREAK)==0 && c==CEOT)
552*39Sbill 			return;
553*39Sbill 	} else {
554*39Sbill 		VOID putc(c, &tp->t_outq);
555*39Sbill 		return;
556*39Sbill 	}
557*39Sbill 
558*39Sbill 	/*
559*39Sbill 	 * Turn tabs to spaces as required
560*39Sbill 	 */
561*39Sbill 	if (c=='\t' && (tp->t_flags&TBDELAY)==XTABS) {
562*39Sbill 		c = 8;
563*39Sbill 		do
564*39Sbill 			ttyoutput(' ', tp);
565*39Sbill 		while (--c >= 0 && tp->t_col&07);
566*39Sbill 		return;
567*39Sbill 	}
568*39Sbill 	/*
569*39Sbill 	 * for upper-case-only terminals,
570*39Sbill 	 * generate escapes.
571*39Sbill 	 */
572*39Sbill 	if (tp->t_flags&LCASE) {
573*39Sbill 		colp = "({)}!|^~'`";
574*39Sbill 		while(*colp++)
575*39Sbill 			if(c == *colp++) {
576*39Sbill 				ttyoutput('\\', tp);
577*39Sbill 				c = colp[-2];
578*39Sbill 				break;
579*39Sbill 			}
580*39Sbill 		if ('a'<=c && c<='z')
581*39Sbill 			c += 'A' - 'a';
582*39Sbill 	}
583*39Sbill 	/*
584*39Sbill 	 * turn <nl> to <cr><lf> if desired.
585*39Sbill 	 */
586*39Sbill 	if (c=='\n' && tp->t_flags&CRMOD)
587*39Sbill 		ttyoutput('\r', tp);
588*39Sbill 	VOID putc(c, &tp->t_outq);
589*39Sbill 	/*
590*39Sbill 	 * Calculate delays.
591*39Sbill 	 * The numbers here represent clock ticks
592*39Sbill 	 * and are not necessarily optimal for all terminals.
593*39Sbill 	 * The delays are indicated by characters above 0200.
594*39Sbill 	 * In raw mode there are no delays and the
595*39Sbill 	 * transmission path is 8 bits wide.
596*39Sbill 	 */
597*39Sbill 	colp = &tp->t_col;
598*39Sbill 	ctype = partab[c];
599*39Sbill 	c = 0;
600*39Sbill 	switch (ctype&077) {
601*39Sbill 
602*39Sbill 	/* ordinary */
603*39Sbill 	case 0:
604*39Sbill 		(*colp)++;
605*39Sbill 
606*39Sbill 	/* non-printing */
607*39Sbill 	case 1:
608*39Sbill 		break;
609*39Sbill 
610*39Sbill 	/* backspace */
611*39Sbill 	case 2:
612*39Sbill 		if (*colp)
613*39Sbill 			(*colp)--;
614*39Sbill 		break;
615*39Sbill 
616*39Sbill 	/* newline */
617*39Sbill 	case 3:
618*39Sbill 		ctype = (tp->t_flags >> 8) & 03;
619*39Sbill 		if(ctype == 1) { /* tty 37 */
620*39Sbill 			if (*colp)
621*39Sbill 				c = max(((unsigned)*colp>>4) + 3, (unsigned)6);
622*39Sbill 		} else
623*39Sbill 		if(ctype == 2) { /* vt05 */
624*39Sbill 			c = 6;
625*39Sbill 		}
626*39Sbill 		*colp = 0;
627*39Sbill 		break;
628*39Sbill 
629*39Sbill 	/* tab */
630*39Sbill 	case 4:
631*39Sbill 		ctype = (tp->t_flags >> 10) & 03;
632*39Sbill 		if(ctype == 1) { /* tty 37 */
633*39Sbill 			c = 1 - (*colp | ~07);
634*39Sbill 			if(c < 5)
635*39Sbill 				c = 0;
636*39Sbill 		}
637*39Sbill 		*colp |= 07;
638*39Sbill 		(*colp)++;
639*39Sbill 		break;
640*39Sbill 
641*39Sbill 	/* vertical motion */
642*39Sbill 	case 5:
643*39Sbill 		if(tp->t_flags & VTDELAY) /* tty 37 */
644*39Sbill 			c = 0177;
645*39Sbill 		break;
646*39Sbill 
647*39Sbill 	/* carriage return */
648*39Sbill 	case 6:
649*39Sbill 		ctype = (tp->t_flags >> 12) & 03;
650*39Sbill 		if(ctype == 1) { /* tn 300 */
651*39Sbill 			c = 5;
652*39Sbill 		} else if(ctype == 2) { /* ti 700 */
653*39Sbill 			c = 10;
654*39Sbill 		} else if(ctype == 3) { /* concept 100 */
655*39Sbill 			int i;
656*39Sbill 			for (i= *colp; i<9; i++)
657*39Sbill 				VOID putc(0177, &tp->t_outq);
658*39Sbill 		}
659*39Sbill 		*colp = 0;
660*39Sbill 	}
661*39Sbill 	if(c)
662*39Sbill 		VOID putc(c|0200, &tp->t_outq);
663*39Sbill }
664*39Sbill 
665*39Sbill /*
666*39Sbill  * Restart typewriter output following a delay
667*39Sbill  * timeout.
668*39Sbill  * The name of the routine is passed to the timeout
669*39Sbill  * subroutine and it is called during a clock interrupt.
670*39Sbill  */
671*39Sbill ttrstrt(tp)
672*39Sbill register struct tty *tp;
673*39Sbill {
674*39Sbill 
675*39Sbill 	tp->t_state &= ~TIMEOUT;
676*39Sbill 	ttstart(tp);
677*39Sbill }
678*39Sbill 
679*39Sbill /*
680*39Sbill  * Start output on the typewriter. It is used from the top half
681*39Sbill  * after some characters have been put on the output queue,
682*39Sbill  * from the interrupt routine to transmit the next
683*39Sbill  * character, and after a timeout has finished.
684*39Sbill  */
685*39Sbill ttstart(tp)
686*39Sbill register struct tty *tp;
687*39Sbill {
688*39Sbill 	register s;
689*39Sbill 
690*39Sbill 	s = spl5();
691*39Sbill 	if((tp->t_state&(TIMEOUT|TTSTOP|BUSY)) == 0)
692*39Sbill 		(*tp->t_oproc)(tp);
693*39Sbill 	splx(s);
694*39Sbill }
695*39Sbill 
696*39Sbill /*
697*39Sbill  * Called from device's read routine after it has
698*39Sbill  * calculated the tty-structure given as argument.
699*39Sbill  */
700*39Sbill ttread(tp)
701*39Sbill register struct tty *tp;
702*39Sbill {
703*39Sbill register s;
704*39Sbill 
705*39Sbill 	if ((tp->t_state&CARR_ON)==0)
706*39Sbill 		return(-1);
707*39Sbill 	s = spl5();
708*39Sbill 	if (tp->t_canq.c_cc==0)
709*39Sbill 		while (canon(tp)<0)
710*39Sbill 			if (tp->t_chan==NULL) {
711*39Sbill 				sleep((caddr_t)&tp->t_rawq, TTIPRI);
712*39Sbill 			} else {
713*39Sbill 				splx(s);
714*39Sbill 				return(0);
715*39Sbill 			}
716*39Sbill 	splx(s);
717*39Sbill 	while (tp->t_canq.c_cc && passc(getc(&tp->t_canq))>=0)
718*39Sbill 			;
719*39Sbill 	return(tp->t_rawq.c_cc+tp->t_canq.c_cc);
720*39Sbill }
721*39Sbill 
722*39Sbill /*
723*39Sbill  * Called from the device's write routine after it has
724*39Sbill  * calculated the tty-structure given as argument.
725*39Sbill  */
726*39Sbill caddr_t
727*39Sbill ttwrite(tp)
728*39Sbill register struct tty *tp;
729*39Sbill {
730*39Sbill 	/*
731*39Sbill 	 * THE POSITIONING OF CP, CC, AND CE ARE CRITICAL
732*39Sbill 	 * AND MUST NOT BE CHANGED WITHOUT PATCHING
733*39Sbill 	 * THE 'ASM' INLINES BELOW.  WATCH OUT.
734*39Sbill 	 */
735*39Sbill 	register char *cp;
736*39Sbill 	register int cc, ce;
737*39Sbill 	register i;
738*39Sbill 	char obuf[OBUFSIZ];
739*39Sbill 
740*39Sbill 	if ((tp->t_state&CARR_ON)==0)
741*39Sbill 		return(NULL);
742*39Sbill 	while (u.u_count) {
743*39Sbill 		cc = MIN(u.u_count, OBUFSIZ);
744*39Sbill 		cp = obuf;
745*39Sbill 		iomove(cp, (unsigned)cc, B_WRITE);
746*39Sbill 		if (u.u_error)
747*39Sbill 			break;
748*39Sbill 		VOID spl5();
749*39Sbill 		while (tp->t_outq.c_cc > TTHIWAT) {
750*39Sbill 			ttstart(tp);
751*39Sbill 			tp->t_state |= ASLEEP;
752*39Sbill 			if (tp->t_chan) {
753*39Sbill 				u.u_base -= cc;
754*39Sbill 				u.u_offset -= cc;
755*39Sbill 				u.u_count += cc;
756*39Sbill 				VOID spl0();
757*39Sbill 				return((caddr_t)&tp->t_outq);
758*39Sbill 			}
759*39Sbill 			sleep((caddr_t)&tp->t_outq, TTOPRI);
760*39Sbill 		}
761*39Sbill 		VOID spl0();
762*39Sbill 		if (tp->t_flags&LCASE) {
763*39Sbill 			while (cc--)
764*39Sbill 				ttyoutput(*cp++,tp);
765*39Sbill 			continue;
766*39Sbill 		}
767*39Sbill 		while (cc) {
768*39Sbill 			if (tp->t_flags&RAW)
769*39Sbill 				ce=cc;
770*39Sbill 			else {
771*39Sbill #ifdef VAX
772*39Sbill 				asm("	scanc	r9,(r10),_partab,$077");
773*39Sbill 				asm("	subl3	r0,r9,r8");
774*39Sbill #else
775*39Sbill 				ce=0;
776*39Sbill 				while(((partab[*(cp+ce)]&077)==0)&&(ce<cc))
777*39Sbill 					ce++;
778*39Sbill #endif
779*39Sbill 				if (ce==0) {
780*39Sbill 					ttyoutput(*cp++,tp);
781*39Sbill 					cc--;
782*39Sbill 					continue;
783*39Sbill 				}
784*39Sbill 			}
785*39Sbill 			i=b_to_q(cp,ce,&tp->t_outq);
786*39Sbill 			ce-=i;
787*39Sbill 			tk_nout+=ce;
788*39Sbill 			tp->t_col+=ce;
789*39Sbill 			cp+=ce;
790*39Sbill 			cc-=ce;
791*39Sbill 			if (i) {
792*39Sbill 				VOID spl5();
793*39Sbill 				while (tp->t_outq.c_cc > TTHIWAT) {
794*39Sbill 					ttstart(tp);
795*39Sbill 					tp->t_state |= ASLEEP;
796*39Sbill 					sleep((caddr_t)&tp->t_outq, TTOPRI);
797*39Sbill 				}
798*39Sbill 				VOID spl0();
799*39Sbill 			}
800*39Sbill 		}
801*39Sbill 	}
802*39Sbill 	ttstart(tp);
803*39Sbill 	return(NULL);
804*39Sbill }
805