Bell 32V development
[unix-history] / usr / src / slowsys / sys / tty.c
CommitLineData
0cd33762
TL
1#
2/*
3 * general TTY subroutines
4 */
5#include "../h/param.h"
6#include "../h/systm.h"
7#include "../h/dir.h"
8#include "../h/user.h"
9#include "../h/tty.h"
10#include "../h/proc.h"
11#include "../h/mx.h"
12#include "../h/inode.h"
13#include "../h/file.h"
14#include "../h/reg.h"
15#include "../h/conf.h"
16
17char partab[];
18
19/*
20 * Input mapping table-- if an entry is non-zero, when the
21 * corresponding character is typed preceded by "\" the escape
22 * sequence is replaced by the table value. Mostly used for
23 * upper-case only terminals.
24 */
25char maptab[] =
26{
27 000,000,000,000,CEOT,00,000,000,
28 000,000,000,000,000,000,000,000,
29 000,000,000,000,000,000,000,000,
30 000,000,000,000,000,000,000,000,
31 000,'|',000,000,000,000,000,'`',
32 '{','}',000,000,000,000,000,000,
33 000,000,000,000,000,000,000,000,
34 000,000,000,000,000,000,000,000,
35 000,000,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,
39 000,'A','B','C','D','E','F','G',
40 'H','I','J','K','L','M','N','O',
41 'P','Q','R','S','T','U','V','W',
42 'X','Y','Z',000,000,000,000,000,
43};
44
45/*
46 * routine called on first teletype open.
47 * establishes a process group for distribution
48 * of quits and interrupts from the tty.
49 */
50ttyopen(dev, tp)
51dev_t dev;
52register struct tty *tp;
53{
54 register struct proc *pp;
55
56 pp = u.u_procp;
57 if(pp->p_pgrp == 0) {
58 u.u_ttyp = tp;
59 u.u_ttyd = dev;
60 if (tp->t_pgrp==0)
61 tp->t_pgrp = pp->p_pid;
62 pp->p_pgrp = tp->t_pgrp;
63 }
64 tp->t_state &= ~WOPEN;
65 tp->t_state |= ISOPEN;
66}
67
68/*
69 * clean tp on last close
70 */
71ttyclose(tp)
72register struct tty *tp;
73{
74
75 tp->t_pgrp = 0;
76 wflushtty(tp);
77 tp->t_state = 0;
78}
79
80/*
81 * stty/gtty writearound
82 */
83stty()
84{
85 u.u_arg[2] = u.u_arg[1];
86 u.u_arg[1] = TIOCSETP;
87 ioctl();
88}
89
90gtty()
91{
92 u.u_arg[2] = u.u_arg[1];
93 u.u_arg[1] = TIOCGETP;
94 ioctl();
95}
96
97/*
98 * ioctl system call
99 * Check legality, execute common code, and switch out to individual
100 * device routine.
101 */
102ioctl()
103{
104 register struct file *fp;
105 register struct inode *ip;
106 register struct a {
107 int fdes;
108 int cmd;
109 caddr_t cmarg;
110 } *uap;
111 register dev_t dev;
112 register fmt;
113
114 uap = (struct a *)u.u_ap;
115 if ((fp = getf(uap->fdes)) == NULL)
116 return;
117 if (uap->cmd==FIOCLEX) {
118 u.u_pofile[uap->fdes] |= EXCLOSE;
119 return;
120 }
121 if (uap->cmd==FIONCLEX) {
122 u.u_pofile[uap->fdes] &= ~EXCLOSE;
123 return;
124 }
125 ip = fp->f_inode;
126 fmt = ip->i_mode & IFMT;
127 if (fmt != IFCHR && fmt != IFMPC) {
128 u.u_error = ENOTTY;
129 return;
130 }
131 dev = (dev_t)ip->i_un.i_rdev;
132 (*cdevsw[major(dev)].d_ioctl)(dev, uap->cmd, uap->cmarg, fp->f_flag&(FREAD|FWRITE));
133}
134
135/*
136 * Common code for several tty ioctl commands
137 */
138ttioccomm(com, tp, addr, dev)
139register struct tty *tp;
140caddr_t addr;
141{
142 unsigned t;
143 struct ttiocb iocb;
144 extern int nldisp;
145
146 switch(com) {
147
148 /*
149 * get discipline number
150 */
151 case TIOCGETD:
152 t = tp->t_line;
153 if (copyout((caddr_t)&t, addr, sizeof(t)))
154 u.u_error = EFAULT;
155 break;
156
157 /*
158 * set line discipline
159 */
160 case TIOCSETD:
161 if (copyin(addr, (caddr_t)&t, sizeof(t))) {
162 u.u_error = EFAULT;
163 break;
164 }
165 if (t >= nldisp) {
166 u.u_error = ENXIO;
167 break;
168 }
169 if (tp->t_line)
170 (*linesw[tp->t_line].l_close)(tp);
171 if (t)
172 (*linesw[t].l_open)(dev, tp, addr);
173 if (u.u_error==0)
174 tp->t_line = t;
175 break;
176
177 /*
178 * prevent more opens on channel
179 */
180 case TIOCEXCL:
181 tp->t_state |= XCLUDE;
182 break;
183 case TIOCNXCL:
184 tp->t_state &= ~XCLUDE;
185 break;
186
187 /*
188 * Set new parameters
189 */
190 case TIOCSETP:
191 wflushtty(tp);
192 case TIOCSETN:
193 if (copyin(addr, (caddr_t)&iocb, sizeof(iocb))) {
194 u.u_error = EFAULT;
195 return(1);
196 }
197 tp->t_ispeed = iocb.ioc_ispeed;
198 tp->t_ospeed = iocb.ioc_ospeed;
199 tp->t_erase = iocb.ioc_erase;
200 tp->t_kill = iocb.ioc_kill;
201 tp->t_flags = iocb.ioc_flags;
202 break;
203
204 /*
205 * send current parameters to user
206 */
207 case TIOCGETP:
208 iocb.ioc_ispeed = tp->t_ispeed;
209 iocb.ioc_ospeed = tp->t_ospeed;
210 iocb.ioc_erase = tp->t_erase;
211 iocb.ioc_kill = tp->t_kill;
212 iocb.ioc_flags = tp->t_flags;
213 if (copyout((caddr_t)&iocb, addr, sizeof(iocb)))
214 u.u_error = EFAULT;
215 break;
216
217 /*
218 * Hang up line on last close
219 */
220
221 case TIOCHPCL:
222 tp->t_state |= HUPCLS;
223 break;
224
225 /*
226 * ioctl entries to line discipline
227 */
228 case DIOCSETP:
229 case DIOCGETP:
230 (*linesw[tp->t_line].l_ioctl)(com, tp, addr);
231 break;
232 default:
233 return(0);
234 }
235 return(1);
236}
237
238/*
239 * Wait for output to drain, then flush input waiting.
240 */
241wflushtty(tp)
242register struct tty *tp;
243{
244
245 spl5();
246 while (tp->t_outq.c_cc && tp->t_state&CARR_ON) {
247 (*tp->t_oproc)(tp);
248 tp->t_state |= ASLEEP;
249 sleep((caddr_t)&tp->t_outq, TTOPRI);
250 }
251 flushtty(tp);
252 spl0();
253}
254
255/*
256 * flush all TTY queues
257 */
258flushtty(tp)
259register struct tty *tp;
260{
261 register s;
262
263 while (getc(&tp->t_canq) >= 0)
264 ;
265 while (getc(&tp->t_outq) >= 0)
266 ;
267 wakeup((caddr_t)&tp->t_rawq);
268 wakeup((caddr_t)&tp->t_outq);
269 s = spl5();
270 while (getc(&tp->t_rawq) >= 0)
271 ;
272 tp->t_delct = 0;
273 splx(s);
274}
275
276/*
277 * transfer raw input list to canonical list,
278 * doing erase-kill processing and handling escapes.
279 * It waits until a full line has been typed in cooked mode,
280 * or until any character has been typed in raw mode.
281 */
282canon(tp)
283register struct tty *tp;
284{
285 register char *bp;
286 char *bp1;
287 register int c;
288 int mc;
289
290 spl5();
291 while ((tp->t_flags&(RAW|CBREAK))==0 && tp->t_delct==0
292 || (tp->t_flags&(RAW|CBREAK))!=0 && tp->t_rawq.c_cc==0) {
293 if ((tp->t_state&CARR_ON)==0)
294 return(0);
295 sleep((caddr_t)&tp->t_rawq, TTIPRI);
296 }
297 spl0();
298loop:
299 bp = &canonb[2];
300 while ((c=getc(&tp->t_rawq)) >= 0) {
301 if ((tp->t_flags&(RAW|CBREAK))==0) {
302 if (c==0377) {
303 tp->t_delct--;
304 break;
305 }
306 if (bp[-1]!='\\') {
307 if (c==tp->t_erase) {
308 if (bp > &canonb[2])
309 bp--;
310 continue;
311 }
312 if (c==tp->t_kill)
313 goto loop;
314 if (c==CEOT)
315 continue;
316 } else {
317 mc = maptab[c];
318 if (c==tp->t_erase || c==tp->t_kill)
319 mc = c;
320 if (mc && (mc==c || (tp->t_flags&LCASE))) {
321 if (bp[-2] != '\\')
322 c = mc;
323 bp--;
324 }
325 }
326 }
327 *bp++ = c;
328 if (bp>=canonb+CANBSIZ)
329 break;
330 }
331 bp1 = bp;
332 bp = &canonb[2];
333 while (bp<bp1)
334 putc(*bp++, &tp->t_canq);
335 return(bp1 - &canonb[2]);
336}
337
338/*
339 * Place a character on raw TTY input queue, putting in delimiters
340 * and waking up top half as needed.
341 * Also echo if required.
342 * The arguments are the character and the appropriate
343 * tty structure.
344 */
345ttyinput(c, tp)
346register c;
347register struct tty *tp;
348{
349 register int t_flags;
350 register struct chan *cp;
351
352 tk_nin += 1;
353 c &= 0377;
354 t_flags = tp->t_flags;
355 if ((t_flags&RAW)==0) {
356 c &= 0177;
357 if (c==CSTOP) {
358 tp->t_state ^= TTSTOP;
359 ttstart(tp);
360 return;
361 }
362 tp->t_state &= ~TTSTOP;
363 if (c==CQUIT || c==CINTR) {
364 signal(tp->t_pgrp, c==CINTR? SIGINT:SIGQUIT);
365 flushtty(tp);
366 return;
367 }
368 if (c=='\r' && t_flags&CRMOD)
369 c = '\n';
370 }
371 if (tp->t_rawq.c_cc>TTYHOG) {
372 flushtty(tp);
373 return;
374 }
375 if (t_flags&LCASE && c>='A' && c<='Z')
376 c += 'a'-'A';
377 putc(c, &tp->t_rawq);
378 if (t_flags&(RAW|CBREAK) || (c=='\n' || c==CEOT)) {
379 if ((t_flags&(RAW|CBREAK))==0 && putc(0377, &tp->t_rawq)==0)
380 tp->t_delct++;
381 if (cp = tp->t_chan)
382 sdata(cp);
383 else
384 wakeup((caddr_t)&tp->t_rawq);
385 }
386 if (t_flags&ECHO) {
387 ttyoutput(c, tp);
388 if (c==tp->t_kill && (t_flags&(RAW|CBREAK))==0)
389 ttyoutput('\n', tp);
390 ttstart(tp);
391 }
392}
393
394/*
395 * put character on TTY output queue, adding delays,
396 * expanding tabs, and handling the CR/NL bit.
397 * It is called both from the top half for output, and from
398 * interrupt level for echoing.
399 * The arguments are the character and the tty structure.
400 */
401ttyoutput(c, tp)
402register c;
403register struct tty *tp;
404{
405 register char *colp;
406 register ctype;
407
408 tk_nout += 1;
409 /*
410 * Ignore EOT in normal mode to avoid hanging up
411 * certain terminals.
412 * In raw mode dump the char unchanged.
413 */
414
415 if ((tp->t_flags&RAW)==0) {
416 c &= 0177;
417 if (c==CEOT)
418 return;
419 } else {
420 putc(c, &tp->t_outq);
421 return;
422 }
423 /*
424 * Turn tabs to spaces as required
425 */
426 if (c=='\t' && (tp->t_flags&TBDELAY)==XTABS) {
427 c = 8;
428 do
429 ttyoutput(' ', tp);
430 while (--c >= 0 && tp->t_col&07);
431 return;
432 }
433 /*
434 * for upper-case-only terminals,
435 * generate escapes.
436 */
437 if (tp->t_flags&LCASE) {
438 colp = "({)}!|^~'`";
439 while(*colp++)
440 if(c == *colp++) {
441 ttyoutput('\\', tp);
442 c = colp[-2];
443 break;
444 }
445 if ('a'<=c && c<='z')
446 c += 'A' - 'a';
447 }
448 /*
449 * turn <nl> to <cr><lf> if desired.
450 */
451 if (c=='\n' && tp->t_flags&CRMOD)
452 ttyoutput('\r', tp);
453 putc(c, &tp->t_outq);
454 /*
455 * Calculate delays.
456 * The numbers here represent clock ticks
457 * and are not necessarily optimal for all terminals.
458 * The delays are indicated by characters above 0200.
459 * In raw mode there are no delays and the
460 * transmission path is 8 bits wide.
461 */
462 colp = &tp->t_col;
463 ctype = partab[c];
464 c = 0;
465 switch (ctype&077) {
466
467 /* ordinary */
468 case 0:
469 (*colp)++;
470
471 /* non-printing */
472 case 1:
473 break;
474
475 /* backspace */
476 case 2:
477 if (*colp)
478 (*colp)--;
479 break;
480
481 /* newline */
482 case 3:
483 ctype = (tp->t_flags >> 8) & 03;
484 if(ctype == 1) { /* tty 37 */
485 if (*colp)
486 c = max(((unsigned)*colp>>4) + 3, (unsigned)6);
487 } else
488 if(ctype == 2) { /* vt05 */
489 c = 6;
490 }
491 *colp = 0;
492 break;
493
494 /* tab */
495 case 4:
496 ctype = (tp->t_flags >> 10) & 03;
497 if(ctype == 1) { /* tty 37 */
498 c = 1 - (*colp | ~07);
499 if(c < 5)
500 c = 0;
501 }
502 *colp |= 07;
503 (*colp)++;
504 break;
505
506 /* vertical motion */
507 case 5:
508 if(tp->t_flags & VTDELAY) /* tty 37 */
509 c = 0177;
510 break;
511
512 /* carriage return */
513 case 6:
514 ctype = (tp->t_flags >> 12) & 03;
515 if(ctype == 1) { /* tn 300 */
516 c = 5;
517 } else if(ctype == 2) { /* ti 700 */
518 c = 10;
519 }
520 *colp = 0;
521 }
522 if(c)
523 putc(c|0200, &tp->t_outq);
524}
525
526/*
527 * Restart typewriter output following a delay
528 * timeout.
529 * The name of the routine is passed to the timeout
530 * subroutine and it is called during a clock interrupt.
531 */
532ttrstrt(tp)
533register struct tty *tp;
534{
535
536 tp->t_state &= ~TIMEOUT;
537 ttstart(tp);
538}
539
540/*
541 * Start output on the typewriter. It is used from the top half
542 * after some characters have been put on the output queue,
543 * from the interrupt routine to transmit the next
544 * character, and after a timeout has finished.
545 */
546ttstart(tp)
547register struct tty *tp;
548{
549 register s;
550
551 s = spl5();
552 if((tp->t_state&(TIMEOUT|TTSTOP|BUSY)) == 0)
553 (*tp->t_oproc)(tp);
554 splx(s);
555}
556
557/*
558 * Called from device's read routine after it has
559 * calculated the tty-structure given as argument.
560 */
561ttread(tp)
562register struct tty *tp;
563{
564 struct chan *chan;
565
566 if ((tp->t_state&CARR_ON)==0)
567 return;
568 chan = tp->t_chan;
569 tp->t_chan = NULL;
570 if (tp->t_canq.c_cc || canon(tp))
571 while (tp->t_canq.c_cc && passc(getc(&tp->t_canq))>=0)
572 ;
573 tp->t_chan = chan;
574}
575
576/*
577 * Called from the device's write routine after it has
578 * calculated the tty-structure given as argument.
579 */
580ttwrite(tp)
581register struct tty *tp;
582{
583 register c;
584
585 if ((tp->t_state&CARR_ON)==0)
586 return;
587 while ((c=cpass())>=0) {
588 spl5();
589 while (tp->t_outq.c_cc > TTHIWAT) {
590 ttstart(tp);
591 tp->t_state |= ASLEEP;
592 sleep((caddr_t)&tp->t_outq, TTOPRI);
593 }
594 spl0();
595 ttyoutput(c, tp);
596 }
597 ttstart(tp);
598}