force new version; tty driver fixes and up MOL patch
[unix-history] / usr / src / sys / kern / tty.c
CommitLineData
50450a20 1/* tty.c 3.15 %G% */
89dc6dfb
BJ
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"
d1778415 18#include "../h/dk.h"
89dc6dfb
BJ
19
20char partab[];
21
d3ebf5ee
BJ
22/*
23 * When running dz's using only SAE (silo alarm) on input
24 * it is necessary to call dzrint() at clock interrupt time.
25 * This is unsafe unless spl5()s in tty code are changed to
26 * spl6()s to block clock interrupts. Note that the dh driver
27 * currently in use works the same way as the dz, even though
28 * we could try to more intelligently manage its silo.
29 * Thus don't take this out if you have no dz's unless you
30 * change clock.c and dhtimer().
31 */
32#define spl5 spl6
89dc6dfb
BJ
33
34/*
35 * Input mapping table-- if an entry is non-zero, when the
36 * corresponding character is typed preceded by "\" the escape
37 * sequence is replaced by the table value. Mostly used for
38 * upper-case only terminals.
39 */
40
41char maptab[] ={
42 000,000,000,000,000,000,000,000,
43 000,000,000,000,000,000,000,000,
44 000,000,000,000,000,000,000,000,
45 000,000,000,000,000,000,000,000,
46 000,'|',000,000,000,000,000,'`',
47 '{','}',000,000,000,000,000,000,
48 000,000,000,000,000,000,000,000,
49 000,000,000,000,000,000,000,000,
50 000,000,000,000,000,000,000,000,
51 000,000,000,000,000,000,000,000,
52 000,000,000,000,000,000,000,000,
53 000,000,000,000,000,000,'~',000,
54 000,'A','B','C','D','E','F','G',
55 'H','I','J','K','L','M','N','O',
56 'P','Q','R','S','T','U','V','W',
57 'X','Y','Z',000,000,000,000,000,
58};
59
60
61/*
62 * shorthand
63 */
64#define q1 tp->t_rawq
65#define q2 tp->t_canq
66#define q3 tp->t_outq
67#define q4 tp->t_un.t_ctlq
68
69#define OBUFSIZ 100
70
71/*
72 * routine called on first teletype open.
73 * establishes a process group for distribution
74 * of quits and interrupts from the tty.
75 */
76ttyopen(dev, tp)
77dev_t dev;
78register struct tty *tp;
79{
80 register struct proc *pp;
81
82 pp = u.u_procp;
83 tp->t_dev = dev;
84 if(pp->p_pgrp == 0) {
85 u.u_ttyp = tp;
86 u.u_ttyd = dev;
6fdc0335
BJ
87 if (tp->t_pgrp == 0)
88 tp->t_pgrp = pp->p_pid;
89dc6dfb
BJ
89 pp->p_pgrp = tp->t_pgrp;
90 }
91 tp->t_state &= ~WOPEN;
92 tp->t_state |= ISOPEN;
250cd6a1 93 tp->t_line = 0; /* conservative */
89dc6dfb
BJ
94}
95
89dc6dfb
BJ
96/*
97 * set default control characters.
98 */
99ttychars(tp)
100register struct tty *tp;
101{
8062c8a7 102
89dc6dfb
BJ
103 tun.t_intrc = CINTR;
104 tun.t_quitc = CQUIT;
105 tun.t_startc = CSTART;
106 tun.t_stopc = CSTOP;
107 tun.t_eofc = CEOT;
108 tun.t_brkc = CBRK;
109 tp->t_erase = CERASE;
110 tp->t_kill = CKILL;
8062c8a7 111/* begin local */
6fdc0335
BJ
112 tlun.t_suspc = CTRL(z);
113 tlun.t_dsuspc = CTRL(y);
8062c8a7
BJ
114 tlun.t_rprntc = CTRL(r);
115 tlun.t_flushc = CTRL(o);
116 tlun.t_werasc = CTRL(w);
117 tlun.t_lnextc = CTRL(v);
118 tlun.t_lintr = CTRL(c);
119 tlun.t_lerase = CTRL(h);
120 tlun.t_lkill = CTRL(u);
121 tp->t_local = 0;
122 tp->t_lstate = 0;
123/* end local */
89dc6dfb
BJ
124}
125
126/*
127 * clean tp on last close
128 */
129ttyclose(tp)
130register struct tty *tp;
131{
132
133 tp->t_pgrp = 0;
134 wflushtty(tp);
135 tp->t_state = 0;
250cd6a1 136 tp->t_line = 0;
89dc6dfb
BJ
137}
138
139/*
140 * stty/gtty writearound
141 */
142stty()
143{
144 u.u_arg[2] = u.u_arg[1];
145 u.u_arg[1] = TIOCSETP;
146 ioctl();
147}
148
149gtty()
150{
151 u.u_arg[2] = u.u_arg[1];
152 u.u_arg[1] = TIOCGETP;
153 ioctl();
154}
155
101ba270
BJ
156/*
157 * Do nothing specific version of line
158 * discipline specific ioctl command.
159 */
de857265 160/*ARGSUSED*/
101ba270
BJ
161nullioctl(tp, cmd, addr)
162register struct tty *tp;
163caddr_t addr;
164{
165
166 return (cmd);
167}
168
89dc6dfb
BJ
169/*
170 * ioctl system call
171 * Check legality, execute common code, and switch out to individual
172 * device routine.
173 */
174ioctl()
175{
176 register struct file *fp;
177 register struct inode *ip;
178 register struct a {
179 int fdes;
180 int cmd;
181 caddr_t cmarg;
182 } *uap;
183 register dev_t dev;
184 register fmt;
185
186 uap = (struct a *)u.u_ap;
187 if ((fp = getf(uap->fdes)) == NULL)
188 return;
189 if (uap->cmd==FIOCLEX) {
190 u.u_pofile[uap->fdes] |= EXCLOSE;
191 return;
192 }
193 if (uap->cmd==FIONCLEX) {
194 u.u_pofile[uap->fdes] &= ~EXCLOSE;
195 return;
196 }
197 ip = fp->f_inode;
198 fmt = ip->i_mode & IFMT;
199 if (fmt != IFCHR && fmt != IFMPC) {
8062c8a7
BJ
200/* begin local */
201 if (uap->cmd==FIONREAD && (fmt == IFREG || fmt == IFDIR)) {
202 off_t nread = ip->i_size - fp->f_un.f_offset;
203
204 if (copyout((caddr_t)&nread, uap->cmarg, sizeof(off_t)))
205 u.u_error = EFAULT;
206 } else
207/* end local */
208 u.u_error = ENOTTY;
89dc6dfb
BJ
209 return;
210 }
211 dev = ip->i_un.i_rdev;
212 u.u_r.r_val1 = 0;
213 (*cdevsw[major(dev)].d_ioctl)(dev, uap->cmd, uap->cmarg, fp->f_flag);
214}
215
216/*
217 * Common code for several tty ioctl commands
218 */
219ttioccomm(com, tp, addr, dev)
220register struct tty *tp;
221caddr_t addr;
222{
223 unsigned t;
8062c8a7 224 struct sgttyb iocb;
de857265 225 struct clist tq;
89dc6dfb 226 extern int nldisp;
50450a20 227 register c;
da1392b6 228 int temp;
89dc6dfb
BJ
229
230 switch(com) {
231
232 /*
233 * get discipline number
234 */
235 case TIOCGETD:
236 t = tp->t_line;
237 if (copyout((caddr_t)&t, addr, sizeof(t)))
238 u.u_error = EFAULT;
239 break;
240
241 /*
242 * set line discipline
243 */
244 case TIOCSETD:
245 if (copyin(addr, (caddr_t)&t, sizeof(t))) {
246 u.u_error = EFAULT;
247 break;
248 }
249 if (t >= nldisp) {
250 u.u_error = ENXIO;
251 break;
252 }
8062c8a7 253 (void) spl5();
89dc6dfb
BJ
254 if (tp->t_line)
255 (*linesw[tp->t_line].l_close)(tp);
256 if (t)
257 (*linesw[t].l_open)(dev, tp, addr);
258 if (u.u_error==0)
259 tp->t_line = t;
8062c8a7 260 (void) spl0();
89dc6dfb
BJ
261 break;
262
263 /*
264 * prevent more opens on channel
265 */
266 case TIOCEXCL:
267 tp->t_state |= XCLUDE;
268 break;
269
270 case TIOCNXCL:
271 tp->t_state &= ~XCLUDE;
272 break;
273
274 /*
275 * Set new parameters
276 */
277 case TIOCSETP:
de857265 278 case TIOCSETN:
89dc6dfb
BJ
279 if (copyin(addr, (caddr_t)&iocb, sizeof(iocb))) {
280 u.u_error = EFAULT;
281 return(1);
282 }
101ba270 283 (void) spl5();
8062c8a7
BJ
284 if (tp->t_line == 0) {
285 if (com == TIOCSETP)
286 wflushtty(tp);
287 while (canon(tp)>=0)
288 ;
289 } else if (tp->t_line == NTTYDISC) {
290 if (tp->t_flags&RAW || iocb.sg_flags&RAW ||
291 com == TIOCSETP)
292 wflushtty(tp);
293 else if ((tp->t_flags&CBREAK) != (iocb.sg_flags&CBREAK)) {
294 if (iocb.sg_flags & CBREAK) {
295 catq(&tp->t_rawq, &tp->t_canq);
296 tq = tp->t_rawq;
297 tp->t_rawq = tp->t_canq;
298 tp->t_canq = tq;
299 } else {
300 tp->t_local |= LPENDIN;
301 if (tp->t_canq.c_cc)
302 panic("ioccom canq");
303 if (tp->t_chan)
304 (void) sdata(tp->t_chan);
305 else
306 wakeup((caddr_t)&tp->t_rawq);
307 }
308 }
309 }
89dc6dfb 310 if ((tp->t_state&SPEEDS)==0) {
8062c8a7
BJ
311 tp->t_ispeed = iocb.sg_ispeed;
312 tp->t_ospeed = iocb.sg_ospeed;
89dc6dfb 313 }
8062c8a7
BJ
314 tp->t_erase = iocb.sg_erase;
315 tp->t_kill = iocb.sg_kill;
316 tp->t_flags = iocb.sg_flags;
101ba270 317 (void) spl0();
89dc6dfb
BJ
318 break;
319
320 /*
321 * send current parameters to user
322 */
323 case TIOCGETP:
8062c8a7
BJ
324 iocb.sg_ispeed = tp->t_ispeed;
325 iocb.sg_ospeed = tp->t_ospeed;
326 iocb.sg_erase = tp->t_erase;
327 iocb.sg_kill = tp->t_kill;
328 iocb.sg_flags = tp->t_flags;
89dc6dfb
BJ
329 if (copyout((caddr_t)&iocb, addr, sizeof(iocb)))
330 u.u_error = EFAULT;
331 break;
332
333 /*
334 * Hang up line on last close
335 */
336
337 case TIOCHPCL:
338 tp->t_state |= HUPCLS;
339 break;
340
341 case TIOCFLUSH:
07f8c7d2 342 flushtty(tp, FREAD|FWRITE);
89dc6dfb
BJ
343 break;
344
345 /*
346 * ioctl entries to line discipline
347 */
348 case DIOCSETP:
349 case DIOCGETP:
101ba270
BJ
350 if ((*linesw[tp->t_line].l_ioctl)(com, tp, addr))
351 u.u_error = ENOTTY;
89dc6dfb
BJ
352 break;
353
354 /*
355 * set and fetch special characters
356 */
357 case TIOCSETC:
8062c8a7 358 if (copyin(addr, (caddr_t)&tun, sizeof(struct tchars)))
89dc6dfb
BJ
359 u.u_error = EFAULT;
360 break;
361
362 case TIOCGETC:
8062c8a7
BJ
363 if (copyout((caddr_t)&tun, addr, sizeof(struct tchars)))
364 u.u_error = EFAULT;
365 break;
366
367/* local ioctls */
368 case TIOCSLTC:
369 if (copyin(addr, (caddr_t)&tlun, sizeof (struct ltchars)))
370 u.u_error = EFAULT;
371 break;
372
373 case TIOCGLTC:
374 if (copyout((caddr_t)&tlun, addr, sizeof (struct ltchars)))
375 u.u_error = EFAULT;
376 break;
377
378 case FIONREAD: {
d1778415 379 off_t nread;
8062c8a7 380
d1778415
BJ
381 switch (tp->t_line) {
382
383 case NETLDISC:
384 nread = tp->t_rec ? tp->t_inbuf : 0;
385 break;
386
387 case NTTYDISC:
388 nread = tp->t_canq.c_cc;
389 if (tp->t_flags & (RAW|CBREAK))
390 nread += tp->t_rawq.c_cc;
391 break;
392
393 case 0:
394 /* do something here ... */
395 ;
396 }
8062c8a7
BJ
397 if (copyout((caddr_t)&nread, addr, sizeof (off_t)))
398 u.u_error = EFAULT;
399 break;
400 }
401
402 /*
403 * Should allow SPGRP and GPGRP only if tty open for reading.
404 */
405 case TIOCSPGRP:
da1392b6
BJ
406 if (copyin(addr, (caddr_t)&tp->t_pgrp, sizeof (tp->t_pgrp)))
407 u.u_error = EFAULT;
8062c8a7
BJ
408 break;
409
410 case TIOCGPGRP:
411 if (copyout((caddr_t)&tp->t_pgrp, addr, sizeof(tp->t_pgrp)))
412 u.u_error = EFAULT;
413 break;
414
415 /*
416 * Modify local mode word.
417 */
418 case TIOCLBIS:
da1392b6
BJ
419 if (copyin(addr, (caddr_t)&temp, sizeof (tp->t_local)))
420 u.u_error = EFAULT;
421 else
422 tp->t_local |= temp;
8062c8a7
BJ
423 break;
424
425 case TIOCLBIC:
da1392b6
BJ
426 if (copyin(addr, (caddr_t)&temp, sizeof (tp->t_local)))
427 u.u_error = EFAULT;
428 else
429 tp->t_local &= ~temp;
8062c8a7
BJ
430 break;
431
432 case TIOCLSET:
da1392b6
BJ
433 if (copyin(addr, (caddr_t)&temp, sizeof (tp->t_local)))
434 u.u_error = EFAULT;
435 else
436 tp->t_local = temp;
8062c8a7
BJ
437 break;
438
439 case TIOCLGET:
440 if (copyout((caddr_t)&tp->t_local, addr, sizeof(tp->t_local)))
89dc6dfb
BJ
441 u.u_error = EFAULT;
442 break;
443
0dde1c43
BJ
444 case TIOCOUTQ:
445 if (copyout((caddr_t)&tp->t_outq.c_cc, addr, sizeof(tp->t_outq.c_cc)))
446 u.u_error = EFAULT;
447 break;
448
50450a20
BJ
449 case TIOCSTI:
450 c = fubyte(addr);
451 if (u.u_uid && u.u_ttyp != tp || c < 0)
452 u.u_error = EFAULT;
453 else
454 (*linesw[tp->t_line].l_rint)(c, tp);
455 break;
8062c8a7 456/* end of locals */
50450a20 457
89dc6dfb
BJ
458 default:
459 return(0);
460 }
461 return(1);
462}
463
464/*
465 * Wait for output to drain, then flush input waiting.
466 */
467wflushtty(tp)
468register struct tty *tp;
469{
470
101ba270 471 (void) spl5();
89dc6dfb
BJ
472 while (tp->t_outq.c_cc && tp->t_state&CARR_ON) {
473 (*tp->t_oproc)(tp);
474 tp->t_state |= ASLEEP;
475 sleep((caddr_t)&tp->t_outq, TTOPRI);
476 }
07f8c7d2 477 flushtty(tp, FREAD|FWRITE);
101ba270 478 (void) spl0();
89dc6dfb
BJ
479}
480
481/*
482 * flush all TTY queues
483 */
07f8c7d2 484flushtty(tp, rw)
89dc6dfb
BJ
485register struct tty *tp;
486{
487 register s;
488
d1778415
BJ
489 if (tp->t_line == NETLDISC)
490 return;
101ba270 491 s = spl6();
07f8c7d2
BJ
492 if (rw & FREAD) {
493 while (getc(&tp->t_canq) >= 0)
494 ;
495 wakeup((caddr_t)&tp->t_rawq);
496 }
497 if (rw & FWRITE) {
498 wakeup((caddr_t)&tp->t_outq);
499 tp->t_state &= ~TTSTOP;
500 (*cdevsw[major(tp->t_dev)].d_stop)(tp);
501 while (getc(&tp->t_outq) >= 0)
502 ;
503 }
504 if (rw & FREAD) {
505 while (getc(&tp->t_rawq) >= 0)
506 ;
507 tp->t_delct = 0;
508 tp->t_rocount = 0; /* local */
509 tp->t_rocol = 0;
510 tp->t_lstate = 0;
511 }
89dc6dfb
BJ
512 splx(s);
513}
514
515
516
517/*
518 * transfer raw input list to canonical list,
519 * doing erase-kill processing and handling escapes.
520 * It waits until a full line has been typed in cooked mode,
521 * or until any character has been typed in raw mode.
522 */
523canon(tp)
524register struct tty *tp;
525{
526 register char *bp;
527 char *bp1;
528 register int c;
529 int mc;
530 int s;
531
532 if ((tp->t_flags&(RAW|CBREAK))==0 && tp->t_delct==0
533 || (tp->t_flags&(RAW|CBREAK))!=0 && tp->t_rawq.c_cc==0) {
534 return(-1);
535 }
536 s = spl0();
537loop:
538 bp = &canonb[2];
539 while ((c=getc(&tp->t_rawq)) >= 0) {
540 if ((tp->t_flags&(RAW|CBREAK))==0) {
541 if (c==0377) {
542 tp->t_delct--;
543 break;
544 }
545 if (bp[-1]!='\\') {
546 if (c==tp->t_erase) {
547 if (bp > &canonb[2])
548 bp--;
549 continue;
550 }
551 if (c==tp->t_kill)
552 goto loop;
553 if (c==tun.t_eofc)
554 continue;
555 } else {
556 mc = maptab[c];
557 if (c==tp->t_erase || c==tp->t_kill)
558 mc = c;
559 if (mc && (mc==c || (tp->t_flags&LCASE))) {
560 if (bp[-2] != '\\')
561 c = mc;
562 bp--;
563 }
564 }
565 }
566 *bp++ = c;
567 if (bp>=canonb+CANBSIZ)
568 break;
569 }
570 bp1 = &canonb[2];
101ba270 571 (void) b_to_q(bp1, bp-bp1, &tp->t_canq);
89dc6dfb
BJ
572
573 if (tp->t_state&TBLOCK && tp->t_rawq.c_cc < TTYHOG/5) {
574 if (putc(tun.t_startc, &tp->t_outq)==0) {
575 tp->t_state &= ~TBLOCK;
576 ttstart(tp);
577 }
578 tp->t_char = 0;
579 }
580
581 splx(s);
582 return(0);
583}
584
585
586/*
587 * block transfer input handler.
588 */
589ttyrend(tp, pb, pe)
590register struct tty *tp;
591register char *pb, *pe;
592{
593 int tandem;
594
595 tandem = tp->t_flags&TANDEM;
596 if (tp->t_flags&RAW) {
101ba270 597 (void) b_to_q(pb, pe-pb, &tp->t_rawq);
89dc6dfb 598 if (tp->t_chan)
101ba270 599 (void) sdata(tp->t_chan); else
89dc6dfb
BJ
600 wakeup((caddr_t)&tp->t_rawq);
601 } else {
602 tp->t_flags &= ~TANDEM;
603 while (pb < pe)
604 ttyinput(*pb++, tp);
605 tp->t_flags |= tandem;
606 }
607 if (tandem)
608 ttyblock(tp);
609}
610
611/*
612 * Place a character on raw TTY input queue, putting in delimiters
613 * and waking up top half as needed.
614 * Also echo if required.
615 * The arguments are the character and the appropriate
616 * tty structure.
617 */
618ttyinput(c, tp)
619register c;
620register struct tty *tp;
621{
622 register int t_flags;
623 register struct chan *cp;
624
625 tk_nin += 1;
626 c &= 0377;
627 t_flags = tp->t_flags;
628 if (t_flags&TANDEM)
629 ttyblock(tp);
630 if ((t_flags&RAW)==0) {
631 c &= 0177;
632 if (tp->t_state&TTSTOP) {
633 if (c==tun.t_startc) {
634 tp->t_state &= ~TTSTOP;
635 ttstart(tp);
636 return;
637 }
638 if (c==tun.t_stopc)
639 return;
640 tp->t_state &= ~TTSTOP;
641 ttstart(tp);
642 } else {
643 if (c==tun.t_stopc) {
644 tp->t_state |= TTSTOP;
645 (*cdevsw[major(tp->t_dev)].d_stop)(tp);
646 return;
647 }
648 if (c==tun.t_startc)
649 return;
650 }
651 if (c==tun.t_quitc || c==tun.t_intrc) {
07f8c7d2 652 flushtty(tp, FREAD|FWRITE);
89dc6dfb
BJ
653 c = (c==tun.t_intrc) ? SIGINT:SIGQUIT;
654 if (tp->t_chan)
655 scontrol(tp->t_chan, M_SIG, c);
656 else
8062c8a7 657 gsignal(tp->t_pgrp, c);
89dc6dfb
BJ
658 return;
659 }
660 if (c=='\r' && t_flags&CRMOD)
661 c = '\n';
662 }
663 if (tp->t_rawq.c_cc>TTYHOG) {
07f8c7d2 664 flushtty(tp, FREAD|FWRITE);
89dc6dfb
BJ
665 return;
666 }
667 if (t_flags&LCASE && c>='A' && c<='Z')
668 c += 'a'-'A';
101ba270 669 (void) putc(c, &tp->t_rawq);
89dc6dfb
BJ
670 if (t_flags&(RAW|CBREAK)||(c=='\n'||c==tun.t_eofc||c==tun.t_brkc)) {
671 if ((t_flags&(RAW|CBREAK))==0 && putc(0377, &tp->t_rawq)==0)
672 tp->t_delct++;
673 if ((cp=tp->t_chan)!=NULL)
101ba270 674 (void) sdata(cp); else
89dc6dfb
BJ
675 wakeup((caddr_t)&tp->t_rawq);
676 }
677 if (t_flags&ECHO) {
678 ttyoutput(c, tp);
679 if (c==tp->t_kill && (t_flags&(RAW|CBREAK))==0)
680 ttyoutput('\n', tp);
681 ttstart(tp);
682 }
683}
684
685
686/*
687 * Send stop character on input overflow.
688 */
689ttyblock(tp)
690register struct tty *tp;
691{
692 register x;
693 x = q1.c_cc + q2.c_cc;
694 if (q1.c_cc > TTYHOG) {
07f8c7d2 695 flushtty(tp, FREAD|FWRITE);
89dc6dfb
BJ
696 tp->t_state &= ~TBLOCK;
697 }
698 if (x >= TTYHOG/2) {
699 if (putc(tun.t_stopc, &tp->t_outq)==0) {
700 tp->t_state |= TBLOCK;
701 tp->t_char++;
702 ttstart(tp);
703 }
704 }
705}
706
707/*
708 * put character on TTY output queue, adding delays,
709 * expanding tabs, and handling the CR/NL bit.
710 * It is called both from the top half for output, and from
711 * interrupt level for echoing.
712 * The arguments are the character and the tty structure.
713 */
714ttyoutput(c, tp)
715register c;
716register struct tty *tp;
717{
718 register char *colp;
719 register ctype;
720
89dc6dfb
BJ
721 /*
722 * Ignore EOT in normal mode to avoid hanging up
723 * certain terminals.
724 * In raw mode dump the char unchanged.
725 */
89dc6dfb
BJ
726 if ((tp->t_flags&RAW)==0) {
727 c &= 0177;
728 if ((tp->t_flags&CBREAK)==0 && c==CEOT)
729 return;
730 } else {
101ba270
BJ
731 tk_nout++;
732 (void) putc(c, &tp->t_outq);
89dc6dfb
BJ
733 return;
734 }
735
736 /*
737 * Turn tabs to spaces as required
738 */
739 if (c=='\t' && (tp->t_flags&TBDELAY)==XTABS) {
101ba270
BJ
740 c = 8 - (tp->t_col & 7);
741 (void) b_to_q(" ", c, &tp->t_outq);
742 tp->t_col += c;
743 tk_nout += c;
89dc6dfb
BJ
744 return;
745 }
101ba270 746 tk_nout++;
89dc6dfb
BJ
747 /*
748 * for upper-case-only terminals,
749 * generate escapes.
750 */
751 if (tp->t_flags&LCASE) {
752 colp = "({)}!|^~'`";
753 while(*colp++)
754 if(c == *colp++) {
755 ttyoutput('\\', tp);
756 c = colp[-2];
757 break;
758 }
759 if ('a'<=c && c<='z')
760 c += 'A' - 'a';
761 }
762 /*
763 * turn <nl> to <cr><lf> if desired.
764 */
765 if (c=='\n' && tp->t_flags&CRMOD)
766 ttyoutput('\r', tp);
101ba270 767 (void) putc(c, &tp->t_outq);
89dc6dfb
BJ
768 /*
769 * Calculate delays.
770 * The numbers here represent clock ticks
771 * and are not necessarily optimal for all terminals.
772 * The delays are indicated by characters above 0200.
773 * In raw mode there are no delays and the
774 * transmission path is 8 bits wide.
775 */
776 colp = &tp->t_col;
777 ctype = partab[c];
778 c = 0;
779 switch (ctype&077) {
780
781 /* ordinary */
782 case 0:
783 (*colp)++;
784
785 /* non-printing */
786 case 1:
787 break;
788
789 /* backspace */
790 case 2:
791 if (*colp)
792 (*colp)--;
793 break;
794
795 /* newline */
796 case 3:
797 ctype = (tp->t_flags >> 8) & 03;
798 if(ctype == 1) { /* tty 37 */
799 if (*colp)
800 c = max(((unsigned)*colp>>4) + 3, (unsigned)6);
801 } else
802 if(ctype == 2) { /* vt05 */
803 c = 6;
804 }
805 *colp = 0;
806 break;
807
808 /* tab */
809 case 4:
810 ctype = (tp->t_flags >> 10) & 03;
811 if(ctype == 1) { /* tty 37 */
812 c = 1 - (*colp | ~07);
813 if(c < 5)
814 c = 0;
815 }
816 *colp |= 07;
817 (*colp)++;
818 break;
819
820 /* vertical motion */
821 case 5:
822 if(tp->t_flags & VTDELAY) /* tty 37 */
823 c = 0177;
824 break;
825
826 /* carriage return */
827 case 6:
828 ctype = (tp->t_flags >> 12) & 03;
829 if(ctype == 1) { /* tn 300 */
830 c = 5;
831 } else if(ctype == 2) { /* ti 700 */
832 c = 10;
833 } else if(ctype == 3) { /* concept 100 */
834 int i;
6109e54e
BJ
835 if ((i = *colp) >= 0)
836 for (; i<9; i++)
837 (void) putc(0177, &tp->t_outq);
89dc6dfb
BJ
838 }
839 *colp = 0;
840 }
841 if(c)
101ba270 842 (void) putc(c|0200, &tp->t_outq);
89dc6dfb
BJ
843}
844
845/*
846 * Restart typewriter output following a delay
847 * timeout.
848 * The name of the routine is passed to the timeout
849 * subroutine and it is called during a clock interrupt.
850 */
851ttrstrt(tp)
852register struct tty *tp;
853{
854
855 tp->t_state &= ~TIMEOUT;
856 ttstart(tp);
857}
858
859/*
860 * Start output on the typewriter. It is used from the top half
861 * after some characters have been put on the output queue,
862 * from the interrupt routine to transmit the next
863 * character, and after a timeout has finished.
864 */
865ttstart(tp)
866register struct tty *tp;
867{
868 register s;
869
870 s = spl5();
871 if((tp->t_state&(TIMEOUT|TTSTOP|BUSY)) == 0)
872 (*tp->t_oproc)(tp);
873 splx(s);
874}
875
876/*
877 * Called from device's read routine after it has
878 * calculated the tty-structure given as argument.
879 */
880ttread(tp)
881register struct tty *tp;
882{
883register s;
884
885 if ((tp->t_state&CARR_ON)==0)
886 return(-1);
887 s = spl5();
888 if (tp->t_canq.c_cc==0)
889 while (canon(tp)<0)
890 if (tp->t_chan==NULL) {
891 sleep((caddr_t)&tp->t_rawq, TTIPRI);
892 } else {
893 splx(s);
894 return(0);
895 }
896 splx(s);
897 while (tp->t_canq.c_cc && passc(getc(&tp->t_canq))>=0)
898 ;
899 return(tp->t_rawq.c_cc+tp->t_canq.c_cc);
900}
901
902/*
903 * Called from the device's write routine after it has
904 * calculated the tty-structure given as argument.
905 */
906caddr_t
907ttwrite(tp)
908register struct tty *tp;
909{
910 /*
911 * THE POSITIONING OF CP, CC, AND CE ARE CRITICAL
912 * AND MUST NOT BE CHANGED WITHOUT PATCHING
913 * THE 'ASM' INLINES BELOW. WATCH OUT.
914 */
915 register char *cp;
916 register int cc, ce;
917 register i;
918 char obuf[OBUFSIZ];
919
920 if ((tp->t_state&CARR_ON)==0)
921 return(NULL);
922 while (u.u_count) {
923 cc = MIN(u.u_count, OBUFSIZ);
924 cp = obuf;
925 iomove(cp, (unsigned)cc, B_WRITE);
926 if (u.u_error)
927 break;
101ba270 928 (void) spl5();
89dc6dfb
BJ
929 while (tp->t_outq.c_cc > TTHIWAT) {
930 ttstart(tp);
931 tp->t_state |= ASLEEP;
932 if (tp->t_chan) {
933 u.u_base -= cc;
934 u.u_offset -= cc;
935 u.u_count += cc;
101ba270 936 (void) spl0();
89dc6dfb
BJ
937 return((caddr_t)&tp->t_outq);
938 }
939 sleep((caddr_t)&tp->t_outq, TTOPRI);
940 }
101ba270 941 (void) spl0();
89dc6dfb
BJ
942 if (tp->t_flags&LCASE) {
943 while (cc--)
944 ttyoutput(*cp++,tp);
945 continue;
946 }
947 while (cc) {
948 if (tp->t_flags&RAW)
949 ce=cc;
950 else {
951#ifdef VAX
952 asm(" scanc r9,(r10),_partab,$077");
953 asm(" subl3 r0,r9,r8");
954#else
955 ce=0;
956 while(((partab[*(cp+ce)]&077)==0)&&(ce<cc))
957 ce++;
958#endif
959 if (ce==0) {
960 ttyoutput(*cp++,tp);
961 cc--;
101ba270 962 goto check;
89dc6dfb
BJ
963 }
964 }
965 i=b_to_q(cp,ce,&tp->t_outq);
966 ce-=i;
967 tk_nout+=ce;
968 tp->t_col+=ce;
969 cp+=ce;
970 cc-=ce;
101ba270
BJ
971check:
972 if (tp->t_outq.c_cc > TTHIWAT) {
973 (void) spl5();
89dc6dfb
BJ
974 while (tp->t_outq.c_cc > TTHIWAT) {
975 ttstart(tp);
976 tp->t_state |= ASLEEP;
977 sleep((caddr_t)&tp->t_outq, TTOPRI);
978 }
101ba270 979 (void) spl0();
89dc6dfb
BJ
980 }
981 }
982 }
983 ttstart(tp);
984 return(NULL);
985}