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