xref: /csrg-svn/sys/kern/tty.c (revision 8520)
1*8520Sroot /*	tty.c	4.30	82/10/13	*/
239Sbill 
339Sbill /*
4903Sbill  * TTY subroutines common to more than one line discipline
539Sbill  */
639Sbill #include "../h/param.h"
739Sbill #include "../h/systm.h"
839Sbill #include "../h/dir.h"
939Sbill #include "../h/user.h"
1039Sbill #include "../h/tty.h"
1139Sbill #include "../h/proc.h"
1239Sbill #include "../h/inode.h"
1339Sbill #include "../h/file.h"
1439Sbill #include "../h/reg.h"
1539Sbill #include "../h/conf.h"
1639Sbill #include "../h/buf.h"
17340Sbill #include "../h/dk.h"
187722Swnj #include "../h/uio.h"
198154Sroot #include "../h/kernel.h"
2039Sbill 
217436Skre /*
227436Skre  * Table giving parity for characters and indicating
237436Skre  * character classes to tty driver.  In particular,
247436Skre  * if the low 6 bits are 0, then the character needs
257436Skre  * no special processing on output.
267436Skre  */
2739Sbill 
287436Skre char partab[] = {
297436Skre 	0001,0201,0201,0001,0201,0001,0001,0201,
307436Skre 	0202,0004,0003,0201,0005,0206,0201,0001,
317436Skre 	0201,0001,0001,0201,0001,0201,0201,0001,
327436Skre 	0001,0201,0201,0001,0201,0001,0001,0201,
337436Skre 	0200,0000,0000,0200,0000,0200,0200,0000,
347436Skre 	0000,0200,0200,0000,0200,0000,0000,0200,
357436Skre 	0000,0200,0200,0000,0200,0000,0000,0200,
367436Skre 	0200,0000,0000,0200,0000,0200,0200,0000,
377436Skre 	0200,0000,0000,0200,0000,0200,0200,0000,
387436Skre 	0000,0200,0200,0000,0200,0000,0000,0200,
397436Skre 	0000,0200,0200,0000,0200,0000,0000,0200,
407436Skre 	0200,0000,0000,0200,0000,0200,0200,0000,
417436Skre 	0000,0200,0200,0000,0200,0000,0000,0200,
427436Skre 	0200,0000,0000,0200,0000,0200,0200,0000,
437436Skre 	0200,0000,0000,0200,0000,0200,0200,0000,
447436Skre 	0000,0200,0200,0000,0200,0000,0000,0201,
457436Skre 
467436Skre 	/*
477436Skre 	 * 7 bit ascii ends with the last character above,
487436Skre 	 * but we contine through all 256 codes for the sake
497436Skre 	 * of the tty output routines which use special vax
507436Skre 	 * instructions which need a 256 character trt table.
517436Skre 	 */
527436Skre 
537436Skre 	0007,0007,0007,0007,0007,0007,0007,0007,
547436Skre 	0007,0007,0007,0007,0007,0007,0007,0007,
557436Skre 	0007,0007,0007,0007,0007,0007,0007,0007,
567436Skre 	0007,0007,0007,0007,0007,0007,0007,0007,
577436Skre 	0007,0007,0007,0007,0007,0007,0007,0007,
587436Skre 	0007,0007,0007,0007,0007,0007,0007,0007,
597436Skre 	0007,0007,0007,0007,0007,0007,0007,0007,
607436Skre 	0007,0007,0007,0007,0007,0007,0007,0007,
617436Skre 	0007,0007,0007,0007,0007,0007,0007,0007,
627436Skre 	0007,0007,0007,0007,0007,0007,0007,0007,
637436Skre 	0007,0007,0007,0007,0007,0007,0007,0007,
647436Skre 	0007,0007,0007,0007,0007,0007,0007,0007,
657436Skre 	0007,0007,0007,0007,0007,0007,0007,0007,
667436Skre 	0007,0007,0007,0007,0007,0007,0007,0007,
677436Skre 	0007,0007,0007,0007,0007,0007,0007,0007,
687436Skre 	0007,0007,0007,0007,0007,0007,0007,0007
697436Skre };
707436Skre 
71146Sbill /*
7239Sbill  * Input mapping table-- if an entry is non-zero, when the
7339Sbill  * corresponding character is typed preceded by "\" the escape
7439Sbill  * sequence is replaced by the table value.  Mostly used for
7539Sbill  * upper-case only terminals.
7639Sbill  */
7739Sbill 
7839Sbill char	maptab[] ={
7939Sbill 	000,000,000,000,000,000,000,000,
8039Sbill 	000,000,000,000,000,000,000,000,
8139Sbill 	000,000,000,000,000,000,000,000,
8239Sbill 	000,000,000,000,000,000,000,000,
8339Sbill 	000,'|',000,000,000,000,000,'`',
8439Sbill 	'{','}',000,000,000,000,000,000,
8539Sbill 	000,000,000,000,000,000,000,000,
8639Sbill 	000,000,000,000,000,000,000,000,
8739Sbill 	000,000,000,000,000,000,000,000,
8839Sbill 	000,000,000,000,000,000,000,000,
8939Sbill 	000,000,000,000,000,000,000,000,
9039Sbill 	000,000,000,000,000,000,'~',000,
9139Sbill 	000,'A','B','C','D','E','F','G',
9239Sbill 	'H','I','J','K','L','M','N','O',
9339Sbill 	'P','Q','R','S','T','U','V','W',
9439Sbill 	'X','Y','Z',000,000,000,000,000,
9539Sbill };
9639Sbill 
97925Sbill short	tthiwat[16] =
98925Sbill    { 100,100,100,100,100,100,100,200,200,400,400,400,650,650,650,650 };
99925Sbill short	ttlowat[16] =
100925Sbill    {  30, 30, 30, 30, 30, 30, 30, 50, 50,120,120,120,125,125,125,125 };
101925Sbill 
10239Sbill #define	OBUFSIZ	100
10339Sbill 
10439Sbill /*
10539Sbill  * set default control characters.
10639Sbill  */
10739Sbill ttychars(tp)
1087625Ssam 	register struct tty *tp;
10939Sbill {
110174Sbill 
11139Sbill 	tun.t_intrc = CINTR;
11239Sbill 	tun.t_quitc = CQUIT;
11339Sbill 	tun.t_startc = CSTART;
11439Sbill 	tun.t_stopc = CSTOP;
11539Sbill 	tun.t_eofc = CEOT;
11639Sbill 	tun.t_brkc = CBRK;
11739Sbill 	tp->t_erase = CERASE;
11839Sbill 	tp->t_kill = CKILL;
119174Sbill /* begin local */
120208Sbill 	tlun.t_suspc = CTRL(z);
121208Sbill 	tlun.t_dsuspc = CTRL(y);
122174Sbill 	tlun.t_rprntc = CTRL(r);
123174Sbill 	tlun.t_flushc = CTRL(o);
124174Sbill 	tlun.t_werasc = CTRL(w);
125174Sbill 	tlun.t_lnextc = CTRL(v);
126174Sbill 	tp->t_local = 0;
127174Sbill 	tp->t_lstate = 0;
128174Sbill /* end local */
12939Sbill }
13039Sbill 
13139Sbill /*
132903Sbill  * Wait for output to drain, then flush input waiting.
13339Sbill  */
134903Sbill wflushtty(tp)
1355408Swnj 	register struct tty *tp;
13639Sbill {
13739Sbill 
138903Sbill 	(void) spl5();
1395622Swnj 	while (tp->t_outq.c_cc && tp->t_state&TS_CARR_ON
1405622Swnj 	    && tp->t_oproc) {		/* kludge for pty */
141903Sbill 		(*tp->t_oproc)(tp);
1425408Swnj 		tp->t_state |= TS_ASLEEP;
143903Sbill 		sleep((caddr_t)&tp->t_outq, TTOPRI);
144903Sbill 	}
1455426Swnj 	flushtty(tp, FREAD);
146903Sbill 	(void) spl0();
14739Sbill }
14839Sbill 
14939Sbill /*
150903Sbill  * flush all TTY queues
15139Sbill  */
152903Sbill flushtty(tp, rw)
1537625Ssam 	register struct tty *tp;
15439Sbill {
155903Sbill 	register s;
156903Sbill 
157903Sbill 	s = spl6();
158903Sbill 	if (rw & FREAD) {
159903Sbill 		while (getc(&tp->t_canq) >= 0)
160903Sbill 			;
161903Sbill 		wakeup((caddr_t)&tp->t_rawq);
162903Sbill 	}
163903Sbill 	if (rw & FWRITE) {
164903Sbill 		wakeup((caddr_t)&tp->t_outq);
1655408Swnj 		tp->t_state &= ~TS_TTSTOP;
1665426Swnj 		(*cdevsw[major(tp->t_dev)].d_stop)(tp, rw);
167903Sbill 		while (getc(&tp->t_outq) >= 0)
168903Sbill 			;
169903Sbill 	}
170903Sbill 	if (rw & FREAD) {
171903Sbill 		while (getc(&tp->t_rawq) >= 0)
172903Sbill 			;
173903Sbill 		tp->t_delct = 0;
174903Sbill 		tp->t_rocount = 0;		/* local */
175903Sbill 		tp->t_rocol = 0;
176903Sbill 		tp->t_lstate = 0;
177903Sbill 	}
178903Sbill 	splx(s);
17939Sbill }
18039Sbill 
181903Sbill /*
182903Sbill  * Send stop character on input overflow.
183903Sbill  */
184903Sbill ttyblock(tp)
1857625Ssam 	register struct tty *tp;
18639Sbill {
187903Sbill 	register x;
188903Sbill 	x = tp->t_rawq.c_cc + tp->t_canq.c_cc;
189903Sbill 	if (tp->t_rawq.c_cc > TTYHOG) {
190903Sbill 		flushtty(tp, FREAD|FWRITE);
1915408Swnj 		tp->t_state &= ~TS_TBLOCK;
192903Sbill 	}
193903Sbill 	if (x >= TTYHOG/2) {
194903Sbill 		if (putc(tun.t_stopc, &tp->t_outq)==0) {
1955408Swnj 			tp->t_state |= TS_TBLOCK;
196903Sbill 			tp->t_char++;
197903Sbill 			ttstart(tp);
198903Sbill 		}
199903Sbill 	}
20039Sbill }
20139Sbill 
20239Sbill /*
203903Sbill  * Restart typewriter output following a delay
204903Sbill  * timeout.
205903Sbill  * The name of the routine is passed to the timeout
206903Sbill  * subroutine and it is called during a clock interrupt.
207121Sbill  */
208903Sbill ttrstrt(tp)
2097625Ssam 	register struct tty *tp;
210121Sbill {
211121Sbill 
2123351Swnj 	if (tp == 0) {
2133351Swnj 		printf("ttrstrt: arg was 0!\n");
2143351Swnj 		return;
2153351Swnj 	}
2165408Swnj 	tp->t_state &= ~TS_TIMEOUT;
217903Sbill 	ttstart(tp);
218121Sbill }
219121Sbill 
220121Sbill /*
221903Sbill  * Start output on the typewriter. It is used from the top half
222903Sbill  * after some characters have been put on the output queue,
223903Sbill  * from the interrupt routine to transmit the next
224903Sbill  * character, and after a timeout has finished.
22539Sbill  */
226903Sbill ttstart(tp)
2277625Ssam 	register struct tty *tp;
22839Sbill {
229903Sbill 	register s;
23039Sbill 
231903Sbill 	s = spl5();
2327625Ssam 	if ((tp->t_state&(TS_TIMEOUT|TS_TTSTOP|TS_BUSY)) == 0 &&
2335622Swnj 	    tp->t_oproc)		/* kludge for pty */
234903Sbill 		(*tp->t_oproc)(tp);
235903Sbill 	splx(s);
23639Sbill }
23739Sbill 
23839Sbill /*
239903Sbill  * Common code for tty ioctls.
24039Sbill  */
2411780Sbill /*ARGSUSED*/
2427625Ssam ttioctl(tp, com, data, flag)
2437625Ssam 	register struct tty *tp;
2447625Ssam 	caddr_t data;
24539Sbill {
246*8520Sroot 	int dev = tp->t_dev;
24739Sbill 	extern int nldisp;
24839Sbill 
249903Sbill 	/*
250903Sbill 	 * If the ioctl involves modification,
251903Sbill 	 * insist on being able to write the device,
252903Sbill 	 * and hang if in the background.
253903Sbill 	 */
2547625Ssam 	switch (com) {
25539Sbill 
256915Sbill 	case TIOCSETD:
257915Sbill 	case TIOCSETP:
258915Sbill 	case TIOCSETN:
259903Sbill 	case TIOCFLUSH:
260903Sbill 	case TIOCSETC:
261903Sbill 	case TIOCSLTC:
262903Sbill 	case TIOCSPGRP:
263903Sbill 	case TIOCLBIS:
264903Sbill 	case TIOCLBIC:
265903Sbill 	case TIOCLSET:
266915Sbill /* this is reasonable, but impractical...
267903Sbill 		if ((flag & FWRITE) == 0) {
268903Sbill 			u.u_error = EBADF;
269903Sbill 			return (1);
270903Sbill 		}
271915Sbill  */
272903Sbill 		while (tp->t_line == NTTYDISC &&
273903Sbill 		   u.u_procp->p_pgrp != tp->t_pgrp && tp == u.u_ttyp &&
274903Sbill 		   (u.u_procp->p_flag&SVFORK) == 0 &&
275903Sbill 		   u.u_signal[SIGTTOU] != SIG_IGN &&
2765626Swnj 		   u.u_signal[SIGTTOU] != SIG_HOLD
2775626Swnj /*
2785626Swnj 						   &&
279903Sbill 		   (u.u_procp->p_flag&SDETACH)==0) {
2805626Swnj */
2815626Swnj 		   ) {
282903Sbill 			gsignal(u.u_procp->p_pgrp, SIGTTOU);
283903Sbill 			sleep((caddr_t)&lbolt, TTOPRI);
284903Sbill 		}
285903Sbill 		break;
286903Sbill 	}
287903Sbill 
28839Sbill 	/*
289903Sbill 	 * Process the ioctl.
29039Sbill 	 */
2917625Ssam 	switch (com) {
292903Sbill 
293903Sbill 	/*
294903Sbill 	 * Get discipline number
295903Sbill 	 */
29639Sbill 	case TIOCGETD:
2977625Ssam 		*(int *)data = tp->t_line;
29839Sbill 		break;
29939Sbill 
30039Sbill 	/*
301903Sbill 	 * Set line discipline
30239Sbill 	 */
3037625Ssam 	case TIOCSETD: {
3047625Ssam 		register int t = *(int *)data;
3057625Ssam 
30639Sbill 		if (t >= nldisp) {
30739Sbill 			u.u_error = ENXIO;
30839Sbill 			break;
30939Sbill 		}
310174Sbill 		(void) spl5();
31139Sbill 		if (tp->t_line)
31239Sbill 			(*linesw[tp->t_line].l_close)(tp);
31339Sbill 		if (t)
3147625Ssam 			(*linesw[t].l_open)(dev, tp);
31539Sbill 		if (u.u_error==0)
31639Sbill 			tp->t_line = t;
317174Sbill 		(void) spl0();
31839Sbill 		break;
3197625Ssam 	}
32039Sbill 
32139Sbill 	/*
3225614Swnj 	 * Prevent more opens on channel
3235614Swnj 	 */
3245614Swnj 	case TIOCEXCL:
3255614Swnj 		tp->t_state |= TS_XCLUDE;
3265614Swnj 		break;
3275614Swnj 
3285614Swnj 	case TIOCNXCL:
3295614Swnj 		tp->t_state &= ~TS_XCLUDE;
3305614Swnj 		break;
3315614Swnj 
3325614Swnj 	/*
33339Sbill 	 * Set new parameters
33439Sbill 	 */
33539Sbill 	case TIOCSETP:
3367625Ssam 	case TIOCSETN: {
3377625Ssam 		register struct sgttyb *sg = (struct sgttyb *)data;
3387625Ssam 		struct clist tq;
3397625Ssam 
340121Sbill 		(void) spl5();
3417625Ssam 		if (tp->t_flags&RAW || sg->sg_flags&RAW || com == TIOCSETP)
3424484Swnj 			wflushtty(tp);
3437625Ssam 		else if ((tp->t_flags&CBREAK) != (sg->sg_flags&CBREAK)) {
3447625Ssam 			if (sg->sg_flags & CBREAK) {
3454484Swnj 				catq(&tp->t_rawq, &tp->t_canq);
3464484Swnj 				tq = tp->t_rawq;
3474484Swnj 				tp->t_rawq = tp->t_canq;
3484484Swnj 				tp->t_canq = tq;
3494484Swnj 			} else {
3504484Swnj 				tp->t_local |= LPENDIN;
3514484Swnj 				ttwakeup(tp);
352174Sbill 			}
353174Sbill 		}
3547625Ssam 		tp->t_ispeed = sg->sg_ispeed;
3557625Ssam 		tp->t_ospeed = sg->sg_ospeed;
3567625Ssam 		tp->t_erase = sg->sg_erase;
3577625Ssam 		tp->t_kill = sg->sg_kill;
3587625Ssam 		tp->t_flags = sg->sg_flags;
3593941Sbugs 		if (tp->t_flags & RAW) {
3605408Swnj 			tp->t_state &= ~TS_TTSTOP;
3613941Sbugs 			ttstart(tp);
3623941Sbugs 		}
363121Sbill 		(void) spl0();
36439Sbill 		break;
3657625Ssam 	}
36639Sbill 
36739Sbill 	/*
368903Sbill 	 * Send current parameters to user
36939Sbill 	 */
3707625Ssam 	case TIOCGETP: {
3717625Ssam 		register struct sgttyb *sg = (struct sgttyb *)data;
3727625Ssam 
3737625Ssam 		sg->sg_ispeed = tp->t_ispeed;
3747625Ssam 		sg->sg_ospeed = tp->t_ospeed;
3757625Ssam 		sg->sg_erase = tp->t_erase;
3767625Ssam 		sg->sg_kill = tp->t_kill;
3777625Ssam 		sg->sg_flags = tp->t_flags;
37839Sbill 		break;
3797625Ssam 	}
38039Sbill 
38139Sbill 	/*
38239Sbill 	 * Hang up line on last close
38339Sbill 	 */
38439Sbill 	case TIOCHPCL:
3855408Swnj 		tp->t_state |= TS_HUPCLS;
38639Sbill 		break;
38739Sbill 
3883942Sbugs 	case TIOCFLUSH: {
3897625Ssam 		register int flags = *(int *)data;
3907625Ssam 
3917625Ssam 		if (flags == 0)
3923942Sbugs 			flags = FREAD|FWRITE;
3937625Ssam 		else
3947625Ssam 			flags &= FREAD|FWRITE;
3953942Sbugs 		flushtty(tp, flags);
39639Sbill 		break;
3973944Sbugs 	}
39839Sbill 
3997625Ssam 	case FIONBIO:
4007625Ssam 		if (*(int *)data)
4015408Swnj 			tp->t_state |= TS_NBIO;
4025408Swnj 		else
4035408Swnj 			tp->t_state &= ~TS_NBIO;
4045408Swnj 		break;
4055408Swnj 
4067625Ssam 	case FIOASYNC:
4077625Ssam 		if (*(int *)data)
4086216Swnj 			tp->t_state |= TS_ASYNC;
4096216Swnj 		else
4106216Swnj 			tp->t_state &= ~TS_ASYNC;
4116216Swnj 		break;
4126216Swnj 
41339Sbill 	/*
414903Sbill 	 * Set and fetch special characters
41539Sbill 	 */
41639Sbill 	case TIOCSETC:
4177625Ssam 		bcopy(data, (caddr_t)&tun, sizeof (struct tchars));
41839Sbill 		break;
41939Sbill 
42039Sbill 	case TIOCGETC:
4217625Ssam 		bcopy((caddr_t)&tun, data, sizeof (struct tchars));
42239Sbill 		break;
42339Sbill 
424174Sbill /* local ioctls */
425903Sbill 	/*
426903Sbill 	 * Set/get local special characters.
427903Sbill 	 */
428174Sbill 	case TIOCSLTC:
4297625Ssam 		bcopy(data, (caddr_t)&tlun, sizeof (struct ltchars));
430174Sbill 		break;
431174Sbill 
432174Sbill 	case TIOCGLTC:
4337625Ssam 		bcopy((caddr_t)&tlun, data, sizeof (struct ltchars));
434174Sbill 		break;
435174Sbill 
436903Sbill 	/*
437903Sbill 	 * Return number of characters immediately available.
438903Sbill 	 */
4397625Ssam 	case FIONREAD:
4407625Ssam 		*(off_t *)data = ttnread(tp);
441174Sbill 		break;
442174Sbill 
443174Sbill 	/*
444174Sbill 	 * Should allow SPGRP and GPGRP only if tty open for reading.
445174Sbill 	 */
446174Sbill 	case TIOCSPGRP:
4477625Ssam 		tp->t_pgrp = *(int *)data;
448174Sbill 		break;
449174Sbill 
450174Sbill 	case TIOCGPGRP:
4517625Ssam 		*(int *)data = tp->t_pgrp;
452174Sbill 		break;
453174Sbill 
454174Sbill 	/*
455174Sbill 	 * Modify local mode word.
456174Sbill 	 */
457174Sbill 	case TIOCLBIS:
4587625Ssam 		tp->t_local |= *(int *)data;
459174Sbill 		break;
460174Sbill 
461174Sbill 	case TIOCLBIC:
4627625Ssam 		tp->t_local &= ~(*(int *)data);
463174Sbill 		break;
464174Sbill 
465174Sbill 	case TIOCLSET:
4667625Ssam 		tp->t_local = *(int *)data;
467174Sbill 		break;
468174Sbill 
469174Sbill 	case TIOCLGET:
4707625Ssam 		*(int *)data = tp->t_local;
471174Sbill 		break;
472174Sbill 
4737625Ssam 	case TIOCSTOP: {
4747625Ssam 		int s = spl5();
475213Sbill 
4765573Swnj 		if ((tp->t_state & TS_TTSTOP) == 0) {
4775573Swnj 			tp->t_state |= TS_TTSTOP;
4785573Swnj 			(*cdevsw[major(tp->t_dev)].d_stop)(tp, 0);
4795573Swnj 		}
4807625Ssam 		splx(s);
4815573Swnj 		break;
4827625Ssam 	}
4835573Swnj 
4847625Ssam 	case TIOCSTART: {
4857625Ssam 		int s = spl5();
4867625Ssam 
4875573Swnj 		if ((tp->t_state & TS_TTSTOP) || (tp->t_local & LFLUSHO)) {
4885573Swnj 			tp->t_state &= ~TS_TTSTOP;
4895573Swnj 			tp->t_local &= ~LFLUSHO;
4905573Swnj 			ttstart(tp);
4915573Swnj 		}
4927625Ssam 		splx(s);
4935573Swnj 		break;
4947625Ssam 	}
4955573Swnj 
496174Sbill /* end of locals */
497887Sbill 
49839Sbill 	default:
4997625Ssam 		return (0);
50039Sbill 	}
5017625Ssam 	return (1);
50239Sbill }
5034484Swnj 
5044484Swnj ttnread(tp)
5054484Swnj 	struct tty *tp;
5064484Swnj {
5074484Swnj 	int nread = 0;
5084484Swnj 
5094484Swnj 	if (tp->t_local & LPENDIN)
5104484Swnj 		ttypend(tp);
5114484Swnj 	nread = tp->t_canq.c_cc;
5124484Swnj 	if (tp->t_flags & (RAW|CBREAK))
5134484Swnj 		nread += tp->t_rawq.c_cc;
5144484Swnj 	return (nread);
5154484Swnj }
5164484Swnj 
5175408Swnj ttselect(dev, rw)
5184484Swnj 	dev_t dev;
5195408Swnj 	int rw;
5204484Swnj {
5214484Swnj 	register struct tty *tp = &cdevsw[major(dev)].d_ttys[minor(dev)];
5224484Swnj 	int nread;
5235408Swnj 	int s = spl5();
5244484Swnj 
5255408Swnj 	switch (rw) {
5264484Swnj 
5274484Swnj 	case FREAD:
5284484Swnj 		nread = ttnread(tp);
5294484Swnj 		if (nread > 0)
5305408Swnj 			goto win;
5314938Swnj 		if (tp->t_rsel && tp->t_rsel->p_wchan == (caddr_t)&selwait)
5325408Swnj 			tp->t_state |= TS_RCOLL;
5334484Swnj 		else
5344484Swnj 			tp->t_rsel = u.u_procp;
5355408Swnj 		break;
5364484Swnj 
5375408Swnj 	case FWRITE:
5385408Swnj 		if (tp->t_outq.c_cc <= TTLOWAT(tp))
5395408Swnj 			goto win;
5405408Swnj 		if (tp->t_wsel && tp->t_wsel->p_wchan == (caddr_t)&selwait)
5415408Swnj 			tp->t_state |= TS_WCOLL;
5425408Swnj 		else
5435408Swnj 			tp->t_wsel = u.u_procp;
5445408Swnj 		break;
5454484Swnj 	}
5465408Swnj 	splx(s);
5475408Swnj 	return (0);
5485408Swnj win:
5495408Swnj 	splx(s);
5505408Swnj 	return (1);
5514484Swnj }
5527436Skre 
5537502Sroot #define	OBUFSIZ	100
5547502Sroot 
5557502Sroot /*
5567502Sroot  * routine called on opens while tp->t_line == NTTYDISC
5577502Sroot  * establishes a process group for distribution of
5587502Sroot  * quits and interrupts from the tty.
5597502Sroot  * (actually, pp->p_pgrp can't be 0 when this routine
5607502Sroot  * is called since NTTYDISC is not the default discipline)
5617502Sroot  */
5627502Sroot ttyopen(dev, tp)
5637625Ssam 	dev_t dev;
5647625Ssam 	register struct tty *tp;
5657502Sroot {
5667502Sroot 	register struct proc *pp;
5677502Sroot 
5687502Sroot 	pp = u.u_procp;
5697502Sroot 	tp->t_dev = dev;
5707625Ssam 	if (pp->p_pgrp == 0) {
5717502Sroot 		u.u_ttyp = tp;
5727502Sroot 		u.u_ttyd = dev;
5737502Sroot 		if (tp->t_pgrp == 0)
5747502Sroot 			tp->t_pgrp = pp->p_pid;
5757502Sroot 		pp->p_pgrp = tp->t_pgrp;
5767502Sroot 	}
5777502Sroot 	tp->t_state &= ~TS_WOPEN;
5787502Sroot 	tp->t_state |= TS_ISOPEN;
5797502Sroot 	if (tp->t_line != NTTYDISC)
5807502Sroot 		wflushtty(tp);
5817502Sroot }
5827502Sroot 
5837502Sroot /*
5847502Sroot  * clean tp on last close
5857502Sroot  */
5867502Sroot ttyclose(tp)
5877625Ssam 	register struct tty *tp;
5887502Sroot {
5897502Sroot 
5907502Sroot 	if (tp->t_line) {
5917502Sroot 		wflushtty(tp);
5927502Sroot 		tp->t_line = 0;
5937502Sroot 		return;
5947502Sroot 	}
5957502Sroot 	tp->t_pgrp = 0;
5967502Sroot 	wflushtty(tp);
5977502Sroot 	tp->t_state = 0;
5987502Sroot }
5997502Sroot 
6007502Sroot /*
6017502Sroot  * reinput pending characters after state switch
6027502Sroot  * call at spl5().
6037502Sroot  */
6047502Sroot ttypend(tp)
6057625Ssam 	register struct tty *tp;
6067502Sroot {
6077502Sroot 	struct clist tq;
6087502Sroot 	register c;
6097502Sroot 
6107502Sroot 	tp->t_local &= ~LPENDIN;
6117502Sroot 	tp->t_lstate |= LSTYPEN;
6127502Sroot 	tq = tp->t_rawq;
6137502Sroot 	tp->t_rawq.c_cc = 0;
6147502Sroot 	tp->t_rawq.c_cf = tp->t_rawq.c_cl = 0;
6157502Sroot 	while ((c = getc(&tq)) >= 0)
6167502Sroot 		ttyinput(c, tp);
6177502Sroot 	tp->t_lstate &= ~LSTYPEN;
6187502Sroot }
6197502Sroot 
6207502Sroot /*
6217502Sroot  * Place a character on raw TTY input queue, putting in delimiters
6227502Sroot  * and waking up top half as needed.
6237502Sroot  * Also echo if required.
6247502Sroot  * The arguments are the character and the appropriate
6257502Sroot  * tty structure.
6267502Sroot  */
6277502Sroot ttyinput(c, tp)
6287625Ssam 	register c;
6297625Ssam 	register struct tty *tp;
6307502Sroot {
6317502Sroot 	register int t_flags;
6327502Sroot 	int i;
6337502Sroot 
6347502Sroot 	if (tp->t_local&LPENDIN)
6357502Sroot 		ttypend(tp);
6367502Sroot 	tk_nin++;
6377502Sroot 	c &= 0377;
6387502Sroot 	t_flags = tp->t_flags;
6397502Sroot 	if (t_flags&TANDEM)
6407502Sroot 		ttyblock(tp);
6417502Sroot 	if ((t_flags&RAW)==0) {
6427502Sroot 		if ((tp->t_lstate&LSTYPEN) == 0)
6437502Sroot 			c &= 0177;
6447502Sroot 	/* check for literal nexting very first */
6457502Sroot 		if (tp->t_lstate&LSLNCH) {
6467502Sroot 			c |= 0200;
6477502Sroot 			tp->t_lstate &= ~LSLNCH;
6487502Sroot 		}
6497502Sroot 		if (tp->t_line == NTTYDISC && c==tlun.t_lnextc) {
6507502Sroot 			if (tp->t_flags&ECHO)
6517502Sroot 				ttyout("^\b", tp);
6527502Sroot 			tp->t_lstate |= LSLNCH;
6537502Sroot 	/* check for output control functions */
6547502Sroot 		} else if (c==tun.t_stopc) {
6557502Sroot 			if ((tp->t_state&TS_TTSTOP)==0) {
6567502Sroot 				tp->t_state |= TS_TTSTOP;
6577502Sroot 				(*cdevsw[major(tp->t_dev)].d_stop)(tp, 0);
6587502Sroot 				return;
6597502Sroot 			}
6607502Sroot 			if (c!=tun.t_startc)
6617502Sroot 				return;
6627502Sroot 		} else if (c==tun.t_startc) {
6637502Sroot 			tp->t_state &= ~TS_TTSTOP;
6647502Sroot 			tp->t_local &= ~LFLUSHO;
6657502Sroot 			ttstart(tp);
6667502Sroot 			return;
6677502Sroot 		} else if (tp->t_line == NTTYDISC && c==tlun.t_flushc) {
6687502Sroot 			if (tp->t_local & LFLUSHO)
6697502Sroot 				tp->t_local &= ~LFLUSHO;
6707502Sroot 			else {
6717502Sroot 				flushtty(tp, FWRITE);
6727502Sroot 				ttyecho(c, tp);
6737502Sroot 				if (tp->t_rawq.c_cc+tp->t_canq.c_cc)
6747502Sroot 					ttyretype(tp);
6757502Sroot 				tp->t_local |= LFLUSHO;
6767502Sroot 			}
6777502Sroot 			ttstart(tp);
6787502Sroot 			return;
6797502Sroot 		} else if (c==tun.t_intrc || c==tun.t_quitc ||
6807502Sroot 		    (tp->t_line == NTTYDISC && c==tlun.t_suspc)) {
6817502Sroot 			if ((tp->t_local & LNOFLSH) == 0)
6827502Sroot 				flushtty(tp,
6837502Sroot 				    c==tlun.t_suspc ? FREAD : FREAD|FWRITE);
6847502Sroot 			ttyecho(c, tp);
6857502Sroot 			c = c==tun.t_intrc ? SIGINT :
6867502Sroot 				((c==tun.t_quitc) ? SIGQUIT : SIGTSTP);
6877502Sroot 			ttsignal(tp, c);
6887502Sroot 	/* check for buffer editing functions - cooked mode */
6897502Sroot 		} else if ((t_flags&CBREAK) == 0) {
6907502Sroot 			if ((tp->t_lstate&LSQUOT) &&
6917502Sroot 			    (c==tp->t_erase||c==tp->t_kill)) {
6927502Sroot 				ttyrub(unputc(&tp->t_rawq), tp);
6937502Sroot 				c |= 0200;
6947502Sroot 			}
6957502Sroot 			if (c==tp->t_erase) {
6967502Sroot 				if (tp->t_rawq.c_cc)
6977502Sroot 					ttyrub(unputc(&tp->t_rawq), tp);
6987502Sroot 			} else if (c==tp->t_kill) {
6997502Sroot 				if (tp->t_local&LCRTKIL &&
7007502Sroot 				    tp->t_rawq.c_cc == tp->t_rocount) {
7017502Sroot 					while (tp->t_rawq.c_cc)
7027502Sroot 						ttyrub(unputc(&tp->t_rawq), tp);
7037502Sroot 				} else {
7047502Sroot 					ttyecho(c, tp);
7057502Sroot 					ttyecho('\n', tp);
7067502Sroot 					while (getc(&tp->t_rawq) > 0)
7077502Sroot 						;
7087502Sroot 					tp->t_rocount = 0;
7097502Sroot 				}
7107502Sroot 				tp->t_lstate = 0;
7117502Sroot 			} else if (tp->t_line == NTTYDISC && c==tlun.t_werasc) {
7127502Sroot 				if (tp->t_rawq.c_cc == 0)
7137502Sroot 					goto out;
7147502Sroot 				do {
7157502Sroot 					c = unputc(&tp->t_rawq);
7167502Sroot 					if (c != ' ' && c != '\t')
7177502Sroot 						goto erasenb;
7187502Sroot 					ttyrub(c, tp);
7197502Sroot 				} while (tp->t_rawq.c_cc);
7207502Sroot 				goto out;
7217502Sroot 			    erasenb:
7227502Sroot 				do {
7237502Sroot 					ttyrub(c, tp);
7247502Sroot 					if (tp->t_rawq.c_cc == 0)
7257502Sroot 						goto out;
7267502Sroot 					c = unputc(&tp->t_rawq);
7277502Sroot 				} while (c != ' ' && c != '\t');
7287502Sroot 				(void) putc(c, &tp->t_rawq);
7297502Sroot 			} else if (tp->t_line == NTTYDISC && c==tlun.t_rprntc) {
7307502Sroot 				ttyretype(tp);
7317502Sroot 	/* check for cooked mode input buffer overflow */
7327502Sroot 			} else if (tp->t_rawq.c_cc+tp->t_canq.c_cc >= TTYHOG) {
7337502Sroot 				;
7347502Sroot 	/* put data char in q for user and wakeup if a break char */
7357502Sroot 			} else if (putc(c, &tp->t_rawq) >= 0) {
7367502Sroot 				if (tp->t_rawq.c_cc+tp->t_canq.c_cc==TTYHOG
7377502Sroot 				    && tp->t_line == NTTYDISC)
7387502Sroot 					(void) ttyoutput(CTRL(g), tp);
7397502Sroot 				if (!ttbreakc(c, tp)) {
7407502Sroot 					if (tp->t_rocount++ == 0)
7417502Sroot 						tp->t_rocol = tp->t_col;
7427502Sroot 				} else {
7437502Sroot 					tp->t_rocount = 0;
7447502Sroot 					catq(&tp->t_rawq, &tp->t_canq);
7457502Sroot 					/* IF (TP->T_CHAN) (VOID) SDATA(TP->T_CHAN); */
7467502Sroot 					ttwakeup(tp);
7477502Sroot 				}
7487502Sroot 				tp->t_lstate &= ~LSQUOT;
7497502Sroot 				if (c == '\\')
7507502Sroot 					tp->t_lstate |= LSQUOT;
7517502Sroot 				if (tp->t_lstate&LSERASE) {
7527502Sroot 					tp->t_lstate &= ~LSERASE;
7537502Sroot 					(void) ttyoutput('/', tp);
7547502Sroot 				}
7557502Sroot 				i = tp->t_col;
7567502Sroot 				ttyecho(c, tp);
7577502Sroot 				if (c==tun.t_eofc && tp->t_flags&ECHO) {
7587502Sroot 					i = MIN(2, tp->t_col - i);
7597502Sroot 					while (i > 0) {
7607502Sroot 						(void) ttyoutput('\b', tp);
7617502Sroot 						i--;
7627502Sroot 					}
7637502Sroot 				}
7647502Sroot 			}
7657502Sroot 	/* CBREAK mode */
7667502Sroot 		} else if (tp->t_rawq.c_cc > TTYHOG) {
7677502Sroot 			if (tp->t_outq.c_cc < TTHIWAT(tp) &&
7687502Sroot 			    tp->t_line == NTTYDISC)
7697502Sroot 				(void) ttyoutput(CTRL(g), tp);
7707502Sroot 		} else if (putc(c, &tp->t_rawq) >= 0) {
7717502Sroot 			ttwakeup(tp);
7727502Sroot 			ttyecho(c, tp);
7737502Sroot 		}
7747502Sroot 	/* RAW mode */
7757502Sroot 	} else if (tp->t_rawq.c_cc > TTYHOG)
7767502Sroot 		flushtty(tp, FREAD|FWRITE);
7777502Sroot 	else {
7787502Sroot 		if (putc(c, &tp->t_rawq) >= 0)
7797502Sroot 			ttwakeup(tp);
7807502Sroot 		ttyecho(c, tp);
7817502Sroot 	}
7827502Sroot out:
7837502Sroot 	if (tp->t_local & LDECCTQ && tp->t_state & TS_TTSTOP &&
7847502Sroot 	    tun.t_startc != tun.t_stopc)
7857502Sroot 		return;
7867502Sroot 	tp->t_state &= ~TS_TTSTOP;
7877502Sroot 	tp->t_local &= ~LFLUSHO;
7887502Sroot 	ttstart(tp);
7897502Sroot }
7907502Sroot 
7917502Sroot /*
7927502Sroot  * put character on TTY output queue, adding delays,
7937502Sroot  * expanding tabs, and handling the CR/NL bit.
7947502Sroot  * It is called both from the top half for output, and from
7957502Sroot  * interrupt level for echoing.
7967502Sroot  * The arguments are the character and the tty structure.
7977502Sroot  * Returns < 0 if putc succeeds, otherwise returns char to resend
7987502Sroot  * Must be recursive.
7997502Sroot  */
8007502Sroot ttyoutput(c, tp)
8017502Sroot 	register c;
8027502Sroot 	register struct tty *tp;
8037502Sroot {
8047502Sroot 	register char *colp;
8057502Sroot 	register ctype;
8067502Sroot 
8077502Sroot 	if (tp->t_flags&RAW || tp->t_local&LLITOUT) {
8087502Sroot 		if (tp->t_local&LFLUSHO)
8097502Sroot 			return (-1);
8107502Sroot 		if (putc(c, &tp->t_outq))
8117625Ssam 			return (c);
8127502Sroot 		tk_nout++;
8137502Sroot 		return (-1);
8147502Sroot 	}
8157502Sroot 	/*
8167502Sroot 	 * Ignore EOT in normal mode to avoid hanging up
8177502Sroot 	 * certain terminals.
8187502Sroot 	 */
8197502Sroot 	c &= 0177;
8207502Sroot 	if (c==CEOT && (tp->t_flags&CBREAK)==0)
8217502Sroot 		return (-1);
8227502Sroot 	/*
8237502Sroot 	 * Turn tabs to spaces as required
8247502Sroot 	 */
8257502Sroot 	if (c=='\t' && (tp->t_flags&TBDELAY)==XTABS) {
8267502Sroot 		register int s;
8277502Sroot 
8287502Sroot 		c = 8 - (tp->t_col&7);
8297502Sroot 		if ((tp->t_local&LFLUSHO) == 0) {
8307502Sroot 			s = spl5();		/* don't interrupt tabs */
8317502Sroot 			c -= b_to_q("        ", c, &tp->t_outq);
8327502Sroot 			tk_nout += c;
8337502Sroot 			splx(s);
8347502Sroot 		}
8357502Sroot 		tp->t_col += c;
8367502Sroot 		return (c ? -1 : '\t');
8377502Sroot 	}
8387502Sroot 	tk_nout++;
8397502Sroot 	/*
8407502Sroot 	 * for upper-case-only terminals,
8417502Sroot 	 * generate escapes.
8427502Sroot 	 */
8437502Sroot 	if (tp->t_flags&LCASE) {
8447502Sroot 		colp = "({)}!|^~'`";
8457625Ssam 		while (*colp++)
8467625Ssam 			if (c == *colp++) {
8477502Sroot 				if (ttyoutput('\\', tp) >= 0)
8487502Sroot 					return (c);
8497502Sroot 				c = colp[-2];
8507502Sroot 				break;
8517502Sroot 			}
8527502Sroot 		if ('A'<=c && c<='Z') {
8537502Sroot 			if (ttyoutput('\\', tp) >= 0)
8547502Sroot 				return (c);
8557502Sroot 		} else if ('a'<=c && c<='z')
8567502Sroot 			c += 'A' - 'a';
8577502Sroot 	}
8587502Sroot 	/*
8597502Sroot 	 * turn <nl> to <cr><lf> if desired.
8607502Sroot 	 */
8617502Sroot 	if (c=='\n' && tp->t_flags&CRMOD)
8627502Sroot 		if (ttyoutput('\r', tp) >= 0)
8637502Sroot 			return (c);
8647502Sroot 	if (c=='~' && tp->t_local&LTILDE)
8657502Sroot 		c = '`';
8667502Sroot 	if ((tp->t_local&LFLUSHO) == 0 && putc(c, &tp->t_outq))
8677502Sroot 		return (c);
8687502Sroot 	/*
8697502Sroot 	 * Calculate delays.
8707502Sroot 	 * The numbers here represent clock ticks
8717502Sroot 	 * and are not necessarily optimal for all terminals.
8727502Sroot 	 * The delays are indicated by characters above 0200.
8737502Sroot 	 * In raw mode there are no delays and the
8747502Sroot 	 * transmission path is 8 bits wide.
8757502Sroot 	 */
8767502Sroot 	colp = &tp->t_col;
8777502Sroot 	ctype = partab[c];
8787502Sroot 	c = 0;
8797502Sroot 	switch (ctype&077) {
8807502Sroot 
8817502Sroot 	case ORDINARY:
8827502Sroot 		(*colp)++;
8837502Sroot 
8847502Sroot 	case CONTROL:
8857502Sroot 		break;
8867502Sroot 
8877502Sroot 	case BACKSPACE:
8887502Sroot 		if (*colp)
8897502Sroot 			(*colp)--;
8907502Sroot 		break;
8917502Sroot 
8927502Sroot 	case NEWLINE:
8937502Sroot 		ctype = (tp->t_flags >> 8) & 03;
8947625Ssam 		if (ctype == 1) { /* tty 37 */
8957502Sroot 			if (*colp)
8967502Sroot 				c = max(((unsigned)*colp>>4) + 3, (unsigned)6);
8977502Sroot 		} else
8987625Ssam 		if (ctype == 2) { /* vt05 */
8997502Sroot 			c = 6;
9007502Sroot 		}
9017502Sroot 		*colp = 0;
9027502Sroot 		break;
9037502Sroot 
9047502Sroot 	case TAB:
9057502Sroot 		ctype = (tp->t_flags >> 10) & 03;
9067625Ssam 		if (ctype == 1) { /* tty 37 */
9077502Sroot 			c = 1 - (*colp | ~07);
9087625Ssam 			if (c < 5)
9097502Sroot 				c = 0;
9107502Sroot 		}
9117502Sroot 		*colp |= 07;
9127502Sroot 		(*colp)++;
9137502Sroot 		break;
9147502Sroot 
9157502Sroot 	case VTAB:
9167625Ssam 		if (tp->t_flags & VTDELAY) /* tty 37 */
9177502Sroot 			c = 0177;
9187502Sroot 		break;
9197502Sroot 
9207502Sroot 	case RETURN:
9217502Sroot 		ctype = (tp->t_flags >> 12) & 03;
9227625Ssam 		if (ctype == 1) { /* tn 300 */
9237502Sroot 			c = 5;
9247625Ssam 		} else if (ctype == 2) { /* ti 700 */
9257502Sroot 			c = 10;
9267625Ssam 		} else if (ctype == 3) { /* concept 100 */
9277502Sroot 			int i;
9287502Sroot 			if ((i = *colp) >= 0)
9297502Sroot 				for (; i<9; i++)
9307502Sroot 					(void) putc(0177, &tp->t_outq);
9317502Sroot 		}
9327502Sroot 		*colp = 0;
9337502Sroot 	}
9347625Ssam 	if (c && (tp->t_local&LFLUSHO) == 0)
9357502Sroot 		(void) putc(c|0200, &tp->t_outq);
9367502Sroot 	return (-1);
9377502Sroot }
9387502Sroot 
9397502Sroot /*
9407502Sroot  * Called from device's read routine after it has
9417502Sroot  * calculated the tty-structure given as argument.
9427502Sroot  */
9437722Swnj ttread(tp, uio)
9447625Ssam 	register struct tty *tp;
9457722Swnj 	struct uio *uio;
9467502Sroot {
9477502Sroot 	register struct clist *qp;
9487502Sroot 	register c, first;
949*8520Sroot 	int error = 0;
9507502Sroot 
9517502Sroot 	if ((tp->t_state&TS_CARR_ON)==0)
952*8520Sroot 		return (EIO);
9537502Sroot loop:
9547502Sroot 	(void) spl5();
9557502Sroot 	if (tp->t_local&LPENDIN)
9567502Sroot 		ttypend(tp);
9577502Sroot 	(void) spl0();
9587502Sroot 	while (tp == u.u_ttyp && u.u_procp->p_pgrp != tp->t_pgrp) {
9597502Sroot 		if (u.u_signal[SIGTTIN] == SIG_IGN ||
9607502Sroot 		    u.u_signal[SIGTTIN] == SIG_HOLD ||
9617502Sroot /*
9627502Sroot 		    (u.u_procp->p_flag&SDETACH) ||
9637502Sroot */
9647502Sroot 		    u.u_procp->p_flag&SVFORK)
965*8520Sroot 			return (EIO);
9667502Sroot 		gsignal(u.u_procp->p_pgrp, SIGTTIN);
9677502Sroot 		sleep((caddr_t)&lbolt, TTIPRI);
9687502Sroot 	}
9697502Sroot 	if (tp->t_flags&RAW) {
9707502Sroot 		(void) spl5();
9717502Sroot 		if (tp->t_rawq.c_cc <= 0) {
9727502Sroot 			if ((tp->t_state&TS_CARR_ON)==0 ||
9737502Sroot 			    (tp->t_state&TS_NBIO)) {
9747502Sroot 				(void) spl0();
975*8520Sroot 				return (EWOULDBLOCK);
9767502Sroot 			}
9777502Sroot 			sleep((caddr_t)&tp->t_rawq, TTIPRI);
9787502Sroot 			(void) spl0();
9797502Sroot 			goto loop;
9807502Sroot 		}
9817502Sroot 		(void) spl0();
9827722Swnj 		while (tp->t_rawq.c_cc && uio->uio_iovcnt) {
983*8520Sroot 			error = passuc(getc(&tp->t_rawq), uio);
984*8520Sroot 			if (error)
9857722Swnj 				break;
9867722Swnj 		}
987*8520Sroot 		return (error);
9887502Sroot 	} else {
9897502Sroot 		qp = tp->t_flags & CBREAK ? &tp->t_rawq : &tp->t_canq;
9907502Sroot 		(void) spl5();
9917502Sroot 		if (qp->c_cc <= 0) {
9927502Sroot 			if ((tp->t_state&TS_CARR_ON)==0 ||
9937502Sroot 			    (tp->t_state&TS_NBIO)) {
9947502Sroot 				(void) spl0();
995*8520Sroot 				return (EWOULDBLOCK);
9967502Sroot 			}
9977502Sroot 			sleep((caddr_t)&tp->t_rawq, TTIPRI);
9987502Sroot 			(void) spl0();
9997502Sroot 			goto loop;
10007502Sroot 		}
10017502Sroot 		(void) spl0();
10027502Sroot 		first = 1;
10037502Sroot 		while ((c = getc(qp)) >= 0) {
10047502Sroot 			if (tp->t_flags&CRMOD && c == '\r')
10057502Sroot 				c = '\n';
10067502Sroot 			if (tp->t_flags&LCASE && c <= 0177)
10077502Sroot 				if (tp->t_lstate&LSBKSL) {
10087502Sroot 					if (maptab[c])
10097502Sroot 						c = maptab[c];
10107502Sroot 					tp->t_lstate &= ~LSBKSL;
10117502Sroot 				} else if (c >= 'A' && c <= 'Z')
10127502Sroot 					c += 'a' - 'A';
10137502Sroot 				else if (c == '\\') {
10147502Sroot 					tp->t_lstate |= LSBKSL;
10157502Sroot 					continue;
10167502Sroot 				}
10177658Ssam 			if (tp->t_line == NTTYDISC && c == tlun.t_dsuspc) {
10187502Sroot 				ttsignal(tp, SIGTSTP);
10197502Sroot 				if (first) {
10207502Sroot 					sleep((caddr_t)&lbolt, TTIPRI);
10217502Sroot 					goto loop;
10227502Sroot 				}
10237502Sroot 				break;
10247502Sroot 			}
10257502Sroot 			if (c == tun.t_eofc && (tp->t_flags&CBREAK)==0)
10267502Sroot 				break;
1027*8520Sroot 			error = passuc(c & 0177, uio);
1028*8520Sroot 			if (error)
10297502Sroot 				break;
10307722Swnj 			if (uio->uio_iovcnt == 0)
10317722Swnj 				break;
10327502Sroot 			if ((tp->t_flags&CBREAK)==0 && ttbreakc(c, tp))
10337502Sroot 				break;
10347502Sroot 			first = 0;
10357502Sroot 		}
10367502Sroot 		tp->t_lstate &= ~LSBKSL;
10377502Sroot 	}
10387502Sroot 	if (tp->t_state&TS_TBLOCK && tp->t_rawq.c_cc < TTYHOG/5) {
10397502Sroot 		if (putc(tun.t_startc, &tp->t_outq)==0) {
10407502Sroot 			tp->t_state &= ~TS_TBLOCK;
10417502Sroot 			ttstart(tp);
10427502Sroot 		}
10437502Sroot 		tp->t_char = 0;
10447502Sroot 	}
1045*8520Sroot 	return (error);
10467502Sroot }
10477502Sroot 
10487502Sroot /*
10497502Sroot  * Called from the device's write routine after it has
10507502Sroot  * calculated the tty-structure given as argument.
10517502Sroot  */
10527822Sroot ttwrite(tp, uio)
10537625Ssam 	register struct tty *tp;
10547822Sroot 	struct uio *uio;
10557502Sroot {
10567502Sroot #ifdef vax
10577502Sroot 	/*
10587502Sroot 	 * THE POSITIONING OF CP, CC, AND CE ARE CRITICAL
10597502Sroot 	 * AND MUST NOT BE CHANGED WITHOUT PATCHING
10607502Sroot 	 * THE 'ASM' INLINES BELOW.  WATCH OUT.
10617502Sroot 	 */
10627502Sroot #endif
10637502Sroot 	register char *cp;
10647502Sroot 	register int cc, ce;
10657502Sroot 	register i;
10667502Sroot 	char obuf[OBUFSIZ];
10677502Sroot 	register c;
10687502Sroot 	int hiwat = TTHIWAT(tp);
10697822Sroot 	int cnt = uio->uio_resid;
1070*8520Sroot 	int error = 0;
10717502Sroot 
10727502Sroot 	if ((tp->t_state&TS_CARR_ON)==0)
1073*8520Sroot 		return (EIO);
10747502Sroot loop:
10757502Sroot 	while (u.u_procp->p_pgrp != tp->t_pgrp && tp == u.u_ttyp &&
10767502Sroot 	    (tp->t_local&LTOSTOP) && (u.u_procp->p_flag&SVFORK)==0 &&
10777502Sroot 	    u.u_signal[SIGTTOU] != SIG_IGN &&
10787502Sroot 	    u.u_signal[SIGTTOU] != SIG_HOLD
10797502Sroot /*
10807502Sroot 					     &&
10817502Sroot 	    (u.u_procp->p_flag&SDETACH)==0) {
10827502Sroot */
10837502Sroot 	    ) {
10847502Sroot 		gsignal(u.u_procp->p_pgrp, SIGTTOU);
10857502Sroot 		sleep((caddr_t)&lbolt, TTIPRI);
10867502Sroot 	}
10877822Sroot 	while (uio->uio_resid > 0) {
10887822Sroot 		cc = uio->uio_iov->iov_len;
10897822Sroot 		if (cc == 0) {
10907822Sroot 			uio->uio_iovcnt--;
10917822Sroot 			uio->uio_iov++;
10927822Sroot 			if (uio->uio_iovcnt < 0)
10937822Sroot 				panic("ttwrite");
10947822Sroot 			continue;
10957822Sroot 		}
10967822Sroot 		if (cc > OBUFSIZ)
10977822Sroot 			cc = OBUFSIZ;
10987502Sroot 		cp = obuf;
1099*8520Sroot 		error = uiomove(cp, cc, UIO_WRITE, uio);
1100*8520Sroot 		if (error)
11017502Sroot 			break;
11027502Sroot 		if (tp->t_outq.c_cc > hiwat)
11037502Sroot 			goto ovhiwat;
11047502Sroot 		if (tp->t_local&LFLUSHO)
11057502Sroot 			continue;
11067502Sroot 		if (tp->t_flags&LCASE || tp->t_local&LTILDE) {
11077502Sroot 			while (cc) {
11087502Sroot 				c = *cp++;
11097502Sroot 				tp->t_rocount = 0;
11107625Ssam 				while ((c = ttyoutput(c, tp)) >= 0) {
11117502Sroot 					/* out of clists, wait a bit */
11127502Sroot 					ttstart(tp);
11137502Sroot 					sleep((caddr_t)&lbolt, TTOPRI);
11147502Sroot 					tp->t_rocount = 0;
11157502Sroot 				}
11167502Sroot 				--cc;
11177502Sroot 				if (tp->t_outq.c_cc > hiwat)
11187502Sroot 					goto ovhiwat;
11197502Sroot 			}
11207502Sroot 			continue;
11217502Sroot 		}
11227502Sroot 		while (cc) {
11237502Sroot 			if (tp->t_flags&RAW || tp->t_local&LLITOUT)
11247502Sroot 				ce = cc;
11257502Sroot 			else {
11267502Sroot #ifdef vax
11277502Sroot 				asm("	scanc	r9,(r10),_partab,$077");
11287502Sroot 				asm("	subl3	r0,r9,r8");
11297502Sroot #else
11307502Sroot 				ce=0;
11317625Ssam 				while (((partab[*(unsigned char *)(cp+ce)]&077)==0)&&(ce<cc))
11327502Sroot 					ce++;
11337502Sroot #endif
11347502Sroot 				if (ce==0) {
11357502Sroot 					tp->t_rocount = 0;
11367502Sroot 					if (ttyoutput(*cp, tp) >= 0) {
11377502Sroot 						ttstart(tp);
11387502Sroot 						sleep((caddr_t)&lbolt, TTOPRI);
11397502Sroot 						continue;
11407502Sroot 					}
11417502Sroot 					cp++;
11427502Sroot 					cc--;
11437502Sroot 					if (tp->t_outq.c_cc > hiwat)
11447502Sroot 						goto ovhiwat;
11457502Sroot 				}
11467502Sroot 			}
11477502Sroot 			tp->t_rocount = 0;
11487502Sroot 			i=b_to_q(cp,ce,&tp->t_outq);
11497502Sroot 			ce-=i;
11507502Sroot 			tk_nout+=ce;
11517502Sroot 			tp->t_col+=ce;
11527502Sroot 			cp+=ce;
11537502Sroot 			cc-=ce;
11547502Sroot 			if (i) {
11557502Sroot 				ttstart(tp);
11567502Sroot 				sleep((caddr_t)&lbolt, TTOPRI);
11577502Sroot 			}
11587502Sroot 			if (ce || tp->t_outq.c_cc > hiwat)
11597502Sroot 				goto ovhiwat;
11607502Sroot 		}
11617502Sroot 	}
11627502Sroot 	ttstart(tp);
1163*8520Sroot 	return (error);
11647502Sroot 
11657502Sroot ovhiwat:
11667502Sroot 	(void) spl5();
11677822Sroot 	uio->uio_iov->iov_base -= cc;
11687822Sroot 	uio->uio_iov->iov_len += cc;
11697822Sroot 	uio->uio_resid += cc;
11707822Sroot 	uio->uio_offset -= cc;
11717502Sroot 	if (tp->t_outq.c_cc <= hiwat) {
11727502Sroot 		(void) spl0();
11737502Sroot 		goto loop;
11747502Sroot 	}
11757502Sroot 	ttstart(tp);
11767502Sroot 	if (tp->t_state & TS_NBIO) {
11777822Sroot 		if (uio->uio_resid == cnt)
1178*8520Sroot 			return (EWOULDBLOCK);
1179*8520Sroot 		return (0);
11807502Sroot 	}
11817502Sroot 	tp->t_state |= TS_ASLEEP;
11827502Sroot 	sleep((caddr_t)&tp->t_outq, TTOPRI);
11837502Sroot 	(void) spl0();
11847502Sroot 	goto loop;
11857502Sroot }
11867502Sroot 
11877502Sroot /*
11887502Sroot  * Rubout one character from the rawq of tp
11897502Sroot  * as cleanly as possible.
11907502Sroot  */
11917502Sroot ttyrub(c, tp)
11927625Ssam 	register c;
11937625Ssam 	register struct tty *tp;
11947502Sroot {
11957502Sroot 	register char *cp;
11967502Sroot 	register int savecol;
11977502Sroot 	int s;
11987502Sroot 	char *nextc();
11997502Sroot 
12007502Sroot 	if ((tp->t_flags&ECHO)==0)
12017502Sroot 		return;
12027502Sroot 	tp->t_local &= ~LFLUSHO;
12037502Sroot 	c &= 0377;
12047502Sroot 	if (tp->t_local&LCRTBS) {
12057502Sroot 		if (tp->t_rocount == 0) {
12067502Sroot 			/*
12077502Sroot 			 * Screwed by ttwrite; retype
12087502Sroot 			 */
12097502Sroot 			ttyretype(tp);
12107502Sroot 			return;
12117502Sroot 		}
12127502Sroot 		if (c==('\t'|0200) || c==('\n'|0200))
12137502Sroot 			ttyrubo(tp, 2);
12147625Ssam 		else switch (partab[c&=0177] & 0177) {
12157502Sroot 
12167502Sroot 		case ORDINARY:
12177502Sroot 			if (tp->t_flags&LCASE && c >= 'A' && c <= 'Z')
12187502Sroot 				ttyrubo(tp, 2);
12197502Sroot 			else
12207502Sroot 				ttyrubo(tp, 1);
12217502Sroot 			break;
12227502Sroot 
12237502Sroot 		case VTAB:
12247502Sroot 		case BACKSPACE:
12257502Sroot 		case CONTROL:
12267502Sroot 		case RETURN:
12277502Sroot 			if (tp->t_local & LCTLECH)
12287502Sroot 				ttyrubo(tp, 2);
12297502Sroot 			break;
12307502Sroot 
12317502Sroot 		case TAB:
12327502Sroot 			if (tp->t_rocount < tp->t_rawq.c_cc) {
12337502Sroot 				ttyretype(tp);
12347502Sroot 				return;
12357502Sroot 			}
12367502Sroot 			s = spl5();
12377502Sroot 			savecol = tp->t_col;
12387502Sroot 			tp->t_lstate |= LSCNTTB;
12397502Sroot 			tp->t_local |= LFLUSHO;
12407502Sroot 			tp->t_col = tp->t_rocol;
12417502Sroot 			for (cp = tp->t_rawq.c_cf; cp; cp = nextc(&tp->t_rawq, cp))
12427502Sroot 				ttyecho(*cp, tp);
12437502Sroot 			tp->t_local &= ~LFLUSHO;
12447502Sroot 			tp->t_lstate &= ~LSCNTTB;
12457502Sroot 			splx(s);
12467502Sroot 			/*
12477502Sroot 			 * savecol will now be length of the tab
12487502Sroot 			 */
12497502Sroot 			savecol -= tp->t_col;
12507502Sroot 			tp->t_col += savecol;
12517502Sroot 			if (savecol > 8)
12527502Sroot 				savecol = 8;		/* overflow screw */
12537502Sroot 			while (--savecol >= 0)
12547502Sroot 				(void) ttyoutput('\b', tp);
12557502Sroot 			break;
12567502Sroot 
12577502Sroot 		default:
12587502Sroot 			panic("ttyrub");
12597502Sroot 		}
12607502Sroot 	} else if (tp->t_local&LPRTERA) {
12617502Sroot 		if ((tp->t_lstate&LSERASE) == 0) {
12627502Sroot 			(void) ttyoutput('\\', tp);
12637502Sroot 			tp->t_lstate |= LSERASE;
12647502Sroot 		}
12657502Sroot 		ttyecho(c, tp);
12667502Sroot 	} else
12677502Sroot 		ttyecho(tp->t_erase, tp);
12687502Sroot 	tp->t_rocount--;
12697502Sroot }
12707502Sroot 
12717502Sroot /*
12727502Sroot  * Crt back over cnt chars perhaps
12737502Sroot  * erasing them.
12747502Sroot  */
12757502Sroot ttyrubo(tp, cnt)
12767625Ssam 	register struct tty *tp;
12777625Ssam 	int cnt;
12787502Sroot {
12797502Sroot 
12807502Sroot 	while (--cnt >= 0)
12817502Sroot 		ttyout(tp->t_local&LCRTERA ? "\b \b" : "\b", tp);
12827502Sroot }
12837502Sroot 
12847502Sroot /*
12857502Sroot  * Reprint the rawq line.
12867502Sroot  * We assume c_cc has already been checked.
12877502Sroot  */
12887502Sroot ttyretype(tp)
12897625Ssam 	register struct tty *tp;
12907502Sroot {
12917502Sroot 	register char *cp;
12927502Sroot 	char *nextc();
12937502Sroot 	int s;
12947502Sroot 
12957502Sroot 	if (tlun.t_rprntc != 0377)
12967502Sroot 		ttyecho(tlun.t_rprntc, tp);
12977502Sroot 	(void) ttyoutput('\n', tp);
12987502Sroot 	s = spl5();
12997502Sroot 	for (cp = tp->t_canq.c_cf; cp; cp = nextc(&tp->t_canq, cp))
13007502Sroot 		ttyecho(*cp, tp);
13017502Sroot 	for (cp = tp->t_rawq.c_cf; cp; cp = nextc(&tp->t_rawq, cp))
13027502Sroot 		ttyecho(*cp, tp);
13037502Sroot 	tp->t_lstate &= ~LSERASE;
13047502Sroot 	splx(s);
13057502Sroot 	tp->t_rocount = tp->t_rawq.c_cc;
13067502Sroot 	tp->t_rocol = 0;
13077502Sroot }
13087502Sroot 
13097502Sroot /*
13107502Sroot  * Echo a typed character to the terminal
13117502Sroot  */
13127502Sroot ttyecho(c, tp)
13137625Ssam 	register c;
13147625Ssam 	register struct tty *tp;
13157502Sroot {
13167502Sroot 
13177502Sroot 	if ((tp->t_lstate & LSCNTTB) == 0)
13187502Sroot 		tp->t_local &= ~LFLUSHO;
13197502Sroot 	if ((tp->t_flags&ECHO) == 0)
13207502Sroot 		return;
13217502Sroot 	c &= 0377;
13227502Sroot 	if (tp->t_flags&RAW) {
13237502Sroot 		(void) ttyoutput(c, tp);
13247502Sroot 		return;
13257502Sroot 	}
13267502Sroot 	if (c == '\r' && tp->t_flags&CRMOD)
13277502Sroot 		c = '\n';
13287502Sroot 	if (tp->t_local&LCTLECH) {
13297502Sroot 		if ((c&0177) <= 037 && c!='\t' && c!='\n' || (c&0177)==0177) {
13307502Sroot 			(void) ttyoutput('^', tp);
13317502Sroot 			c &= 0177;
13327502Sroot 			if (c == 0177)
13337502Sroot 				c = '?';
13347502Sroot 			else if (tp->t_flags&LCASE)
13357502Sroot 				c += 'a' - 1;
13367502Sroot 			else
13377502Sroot 				c += 'A' - 1;
13387502Sroot 		}
13397502Sroot 	}
13407502Sroot 	if ((tp->t_flags&LCASE) && (c >= 'A' && c <= 'Z'))
13417502Sroot 		c += 'a' - 'A';
13427502Sroot 	(void) ttyoutput(c & 0177, tp);
13437502Sroot }
13447502Sroot 
13457502Sroot /*
13467502Sroot  * Is c a break char for tp?
13477502Sroot  */
13487502Sroot ttbreakc(c, tp)
13497625Ssam 	register c;
13507625Ssam 	register struct tty *tp;
13517502Sroot {
13527502Sroot 	return (c == '\n' || c == tun.t_eofc || c == tun.t_brkc ||
13537502Sroot 		c == '\r' && (tp->t_flags&CRMOD));
13547502Sroot }
13557502Sroot 
13567502Sroot /*
13577502Sroot  * send string cp to tp
13587502Sroot  */
13597502Sroot ttyout(cp, tp)
13607625Ssam 	register char *cp;
13617625Ssam 	register struct tty *tp;
13627502Sroot {
13637502Sroot 	register char c;
13647502Sroot 
13657502Sroot 	while (c = *cp++)
13667502Sroot 		(void) ttyoutput(c, tp);
13677502Sroot }
13687502Sroot 
13697502Sroot ttwakeup(tp)
13707502Sroot 	struct tty *tp;
13717502Sroot {
13727502Sroot 
13737502Sroot 	if (tp->t_rsel) {
13747502Sroot 		selwakeup(tp->t_rsel, tp->t_state&TS_RCOLL);
13757502Sroot 		tp->t_state &= ~TS_RCOLL;
13767502Sroot 		tp->t_rsel = 0;
13777502Sroot 	}
13787502Sroot 	wakeup((caddr_t)&tp->t_rawq);
13797502Sroot }
13807502Sroot 
13817502Sroot ttsignal(tp, signo)
13827502Sroot 	struct tty *tp;
13837502Sroot 	int signo;
13847502Sroot {
13857502Sroot 
13867502Sroot 	gsignal(tp->t_pgrp, signo);
13877502Sroot }
1388