now installed, a.out.h, ar not newa.out.h /usr/new/ar
[unix-history] / usr / src / sys / kern / tty.c
CommitLineData
6d27b2c6 1/* tty.c 3.16 %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;
6d27b2c6
BJ
189 if ((fp->f_flag & (FREAD|FWRITE)) == 0) {
190 u.u_error = EBADF;
191 return;
192 }
89dc6dfb
BJ
193 if (uap->cmd==FIOCLEX) {
194 u.u_pofile[uap->fdes] |= EXCLOSE;
195 return;
196 }
197 if (uap->cmd==FIONCLEX) {
198 u.u_pofile[uap->fdes] &= ~EXCLOSE;
199 return;
200 }
201 ip = fp->f_inode;
202 fmt = ip->i_mode & IFMT;
203 if (fmt != IFCHR && fmt != IFMPC) {
8062c8a7
BJ
204/* begin local */
205 if (uap->cmd==FIONREAD && (fmt == IFREG || fmt == IFDIR)) {
206 off_t nread = ip->i_size - fp->f_un.f_offset;
207
208 if (copyout((caddr_t)&nread, uap->cmarg, sizeof(off_t)))
209 u.u_error = EFAULT;
210 } else
211/* end local */
212 u.u_error = ENOTTY;
89dc6dfb
BJ
213 return;
214 }
215 dev = ip->i_un.i_rdev;
216 u.u_r.r_val1 = 0;
217 (*cdevsw[major(dev)].d_ioctl)(dev, uap->cmd, uap->cmarg, fp->f_flag);
218}
219
220/*
221 * Common code for several tty ioctl commands
222 */
223ttioccomm(com, tp, addr, dev)
224register struct tty *tp;
225caddr_t addr;
226{
227 unsigned t;
8062c8a7 228 struct sgttyb iocb;
de857265 229 struct clist tq;
89dc6dfb 230 extern int nldisp;
50450a20 231 register c;
da1392b6 232 int temp;
89dc6dfb
BJ
233
234 switch(com) {
235
236 /*
237 * get discipline number
238 */
239 case TIOCGETD:
240 t = tp->t_line;
241 if (copyout((caddr_t)&t, addr, sizeof(t)))
242 u.u_error = EFAULT;
243 break;
244
245 /*
246 * set line discipline
247 */
248 case TIOCSETD:
249 if (copyin(addr, (caddr_t)&t, sizeof(t))) {
250 u.u_error = EFAULT;
251 break;
252 }
253 if (t >= nldisp) {
254 u.u_error = ENXIO;
255 break;
256 }
8062c8a7 257 (void) spl5();
89dc6dfb
BJ
258 if (tp->t_line)
259 (*linesw[tp->t_line].l_close)(tp);
260 if (t)
261 (*linesw[t].l_open)(dev, tp, addr);
262 if (u.u_error==0)
263 tp->t_line = t;
8062c8a7 264 (void) spl0();
89dc6dfb
BJ
265 break;
266
267 /*
268 * prevent more opens on channel
269 */
270 case TIOCEXCL:
271 tp->t_state |= XCLUDE;
272 break;
273
274 case TIOCNXCL:
275 tp->t_state &= ~XCLUDE;
276 break;
277
278 /*
279 * Set new parameters
280 */
281 case TIOCSETP:
de857265 282 case TIOCSETN:
89dc6dfb
BJ
283 if (copyin(addr, (caddr_t)&iocb, sizeof(iocb))) {
284 u.u_error = EFAULT;
285 return(1);
286 }
101ba270 287 (void) spl5();
8062c8a7
BJ
288 if (tp->t_line == 0) {
289 if (com == TIOCSETP)
290 wflushtty(tp);
291 while (canon(tp)>=0)
292 ;
293 } else if (tp->t_line == NTTYDISC) {
294 if (tp->t_flags&RAW || iocb.sg_flags&RAW ||
295 com == TIOCSETP)
296 wflushtty(tp);
297 else if ((tp->t_flags&CBREAK) != (iocb.sg_flags&CBREAK)) {
298 if (iocb.sg_flags & CBREAK) {
299 catq(&tp->t_rawq, &tp->t_canq);
300 tq = tp->t_rawq;
301 tp->t_rawq = tp->t_canq;
302 tp->t_canq = tq;
303 } else {
304 tp->t_local |= LPENDIN;
305 if (tp->t_canq.c_cc)
306 panic("ioccom canq");
307 if (tp->t_chan)
308 (void) sdata(tp->t_chan);
309 else
310 wakeup((caddr_t)&tp->t_rawq);
311 }
312 }
313 }
89dc6dfb 314 if ((tp->t_state&SPEEDS)==0) {
8062c8a7
BJ
315 tp->t_ispeed = iocb.sg_ispeed;
316 tp->t_ospeed = iocb.sg_ospeed;
89dc6dfb 317 }
8062c8a7
BJ
318 tp->t_erase = iocb.sg_erase;
319 tp->t_kill = iocb.sg_kill;
320 tp->t_flags = iocb.sg_flags;
101ba270 321 (void) spl0();
89dc6dfb
BJ
322 break;
323
324 /*
325 * send current parameters to user
326 */
327 case TIOCGETP:
8062c8a7
BJ
328 iocb.sg_ispeed = tp->t_ispeed;
329 iocb.sg_ospeed = tp->t_ospeed;
330 iocb.sg_erase = tp->t_erase;
331 iocb.sg_kill = tp->t_kill;
332 iocb.sg_flags = tp->t_flags;
89dc6dfb
BJ
333 if (copyout((caddr_t)&iocb, addr, sizeof(iocb)))
334 u.u_error = EFAULT;
335 break;
336
337 /*
338 * Hang up line on last close
339 */
340
341 case TIOCHPCL:
342 tp->t_state |= HUPCLS;
343 break;
344
345 case TIOCFLUSH:
07f8c7d2 346 flushtty(tp, FREAD|FWRITE);
89dc6dfb
BJ
347 break;
348
349 /*
350 * ioctl entries to line discipline
351 */
352 case DIOCSETP:
353 case DIOCGETP:
101ba270
BJ
354 if ((*linesw[tp->t_line].l_ioctl)(com, tp, addr))
355 u.u_error = ENOTTY;
89dc6dfb
BJ
356 break;
357
358 /*
359 * set and fetch special characters
360 */
361 case TIOCSETC:
8062c8a7 362 if (copyin(addr, (caddr_t)&tun, sizeof(struct tchars)))
89dc6dfb
BJ
363 u.u_error = EFAULT;
364 break;
365
366 case TIOCGETC:
8062c8a7
BJ
367 if (copyout((caddr_t)&tun, addr, sizeof(struct tchars)))
368 u.u_error = EFAULT;
369 break;
370
371/* local ioctls */
372 case TIOCSLTC:
373 if (copyin(addr, (caddr_t)&tlun, sizeof (struct ltchars)))
374 u.u_error = EFAULT;
375 break;
376
377 case TIOCGLTC:
378 if (copyout((caddr_t)&tlun, addr, sizeof (struct ltchars)))
379 u.u_error = EFAULT;
380 break;
381
382 case FIONREAD: {
d1778415 383 off_t nread;
8062c8a7 384
d1778415
BJ
385 switch (tp->t_line) {
386
387 case NETLDISC:
388 nread = tp->t_rec ? tp->t_inbuf : 0;
389 break;
390
6d27b2c6
BJ
391 case 0:
392 (void) spl5();
393 while (canon(tp)>=0)
394 ;
395 (void) spl0();
396 /* fall into ... */
397
d1778415
BJ
398 case NTTYDISC:
399 nread = tp->t_canq.c_cc;
400 if (tp->t_flags & (RAW|CBREAK))
401 nread += tp->t_rawq.c_cc;
402 break;
403
d1778415 404 }
8062c8a7
BJ
405 if (copyout((caddr_t)&nread, addr, sizeof (off_t)))
406 u.u_error = EFAULT;
407 break;
408 }
409
410 /*
411 * Should allow SPGRP and GPGRP only if tty open for reading.
412 */
413 case TIOCSPGRP:
da1392b6
BJ
414 if (copyin(addr, (caddr_t)&tp->t_pgrp, sizeof (tp->t_pgrp)))
415 u.u_error = EFAULT;
8062c8a7
BJ
416 break;
417
418 case TIOCGPGRP:
419 if (copyout((caddr_t)&tp->t_pgrp, addr, sizeof(tp->t_pgrp)))
420 u.u_error = EFAULT;
421 break;
422
423 /*
424 * Modify local mode word.
425 */
426 case TIOCLBIS:
da1392b6
BJ
427 if (copyin(addr, (caddr_t)&temp, sizeof (tp->t_local)))
428 u.u_error = EFAULT;
429 else
430 tp->t_local |= temp;
8062c8a7
BJ
431 break;
432
433 case TIOCLBIC:
da1392b6
BJ
434 if (copyin(addr, (caddr_t)&temp, sizeof (tp->t_local)))
435 u.u_error = EFAULT;
436 else
437 tp->t_local &= ~temp;
8062c8a7
BJ
438 break;
439
440 case TIOCLSET:
da1392b6
BJ
441 if (copyin(addr, (caddr_t)&temp, sizeof (tp->t_local)))
442 u.u_error = EFAULT;
443 else
444 tp->t_local = temp;
8062c8a7
BJ
445 break;
446
447 case TIOCLGET:
448 if (copyout((caddr_t)&tp->t_local, addr, sizeof(tp->t_local)))
89dc6dfb
BJ
449 u.u_error = EFAULT;
450 break;
451
0dde1c43
BJ
452 case TIOCOUTQ:
453 if (copyout((caddr_t)&tp->t_outq.c_cc, addr, sizeof(tp->t_outq.c_cc)))
454 u.u_error = EFAULT;
455 break;
456
50450a20
BJ
457 case TIOCSTI:
458 c = fubyte(addr);
459 if (u.u_uid && u.u_ttyp != tp || c < 0)
460 u.u_error = EFAULT;
461 else
462 (*linesw[tp->t_line].l_rint)(c, tp);
463 break;
8062c8a7 464/* end of locals */
50450a20 465
89dc6dfb
BJ
466 default:
467 return(0);
468 }
469 return(1);
470}
471
472/*
473 * Wait for output to drain, then flush input waiting.
474 */
475wflushtty(tp)
476register struct tty *tp;
477{
478
101ba270 479 (void) spl5();
89dc6dfb
BJ
480 while (tp->t_outq.c_cc && tp->t_state&CARR_ON) {
481 (*tp->t_oproc)(tp);
482 tp->t_state |= ASLEEP;
483 sleep((caddr_t)&tp->t_outq, TTOPRI);
484 }
07f8c7d2 485 flushtty(tp, FREAD|FWRITE);
101ba270 486 (void) spl0();
89dc6dfb
BJ
487}
488
489/*
490 * flush all TTY queues
491 */
07f8c7d2 492flushtty(tp, rw)
89dc6dfb
BJ
493register struct tty *tp;
494{
495 register s;
496
d1778415
BJ
497 if (tp->t_line == NETLDISC)
498 return;
101ba270 499 s = spl6();
07f8c7d2
BJ
500 if (rw & FREAD) {
501 while (getc(&tp->t_canq) >= 0)
502 ;
503 wakeup((caddr_t)&tp->t_rawq);
504 }
505 if (rw & FWRITE) {
506 wakeup((caddr_t)&tp->t_outq);
507 tp->t_state &= ~TTSTOP;
508 (*cdevsw[major(tp->t_dev)].d_stop)(tp);
509 while (getc(&tp->t_outq) >= 0)
510 ;
511 }
512 if (rw & FREAD) {
513 while (getc(&tp->t_rawq) >= 0)
514 ;
515 tp->t_delct = 0;
516 tp->t_rocount = 0; /* local */
517 tp->t_rocol = 0;
518 tp->t_lstate = 0;
519 }
89dc6dfb
BJ
520 splx(s);
521}
522
523
524
525/*
526 * transfer raw input list to canonical list,
527 * doing erase-kill processing and handling escapes.
528 * It waits until a full line has been typed in cooked mode,
529 * or until any character has been typed in raw mode.
530 */
531canon(tp)
532register struct tty *tp;
533{
534 register char *bp;
535 char *bp1;
536 register int c;
537 int mc;
538 int s;
539
540 if ((tp->t_flags&(RAW|CBREAK))==0 && tp->t_delct==0
541 || (tp->t_flags&(RAW|CBREAK))!=0 && tp->t_rawq.c_cc==0) {
542 return(-1);
543 }
544 s = spl0();
545loop:
546 bp = &canonb[2];
547 while ((c=getc(&tp->t_rawq)) >= 0) {
548 if ((tp->t_flags&(RAW|CBREAK))==0) {
549 if (c==0377) {
550 tp->t_delct--;
551 break;
552 }
553 if (bp[-1]!='\\') {
554 if (c==tp->t_erase) {
555 if (bp > &canonb[2])
556 bp--;
557 continue;
558 }
559 if (c==tp->t_kill)
560 goto loop;
561 if (c==tun.t_eofc)
562 continue;
563 } else {
564 mc = maptab[c];
565 if (c==tp->t_erase || c==tp->t_kill)
566 mc = c;
567 if (mc && (mc==c || (tp->t_flags&LCASE))) {
568 if (bp[-2] != '\\')
569 c = mc;
570 bp--;
571 }
572 }
573 }
574 *bp++ = c;
575 if (bp>=canonb+CANBSIZ)
576 break;
577 }
578 bp1 = &canonb[2];
101ba270 579 (void) b_to_q(bp1, bp-bp1, &tp->t_canq);
89dc6dfb
BJ
580
581 if (tp->t_state&TBLOCK && tp->t_rawq.c_cc < TTYHOG/5) {
582 if (putc(tun.t_startc, &tp->t_outq)==0) {
583 tp->t_state &= ~TBLOCK;
584 ttstart(tp);
585 }
586 tp->t_char = 0;
587 }
588
589 splx(s);
590 return(0);
591}
592
593
594/*
595 * block transfer input handler.
596 */
597ttyrend(tp, pb, pe)
598register struct tty *tp;
599register char *pb, *pe;
600{
601 int tandem;
602
603 tandem = tp->t_flags&TANDEM;
604 if (tp->t_flags&RAW) {
101ba270 605 (void) b_to_q(pb, pe-pb, &tp->t_rawq);
89dc6dfb 606 if (tp->t_chan)
101ba270 607 (void) sdata(tp->t_chan); else
89dc6dfb
BJ
608 wakeup((caddr_t)&tp->t_rawq);
609 } else {
610 tp->t_flags &= ~TANDEM;
611 while (pb < pe)
612 ttyinput(*pb++, tp);
613 tp->t_flags |= tandem;
614 }
615 if (tandem)
616 ttyblock(tp);
617}
618
619/*
620 * Place a character on raw TTY input queue, putting in delimiters
621 * and waking up top half as needed.
622 * Also echo if required.
623 * The arguments are the character and the appropriate
624 * tty structure.
625 */
626ttyinput(c, tp)
627register c;
628register struct tty *tp;
629{
630 register int t_flags;
631 register struct chan *cp;
632
633 tk_nin += 1;
634 c &= 0377;
635 t_flags = tp->t_flags;
636 if (t_flags&TANDEM)
637 ttyblock(tp);
638 if ((t_flags&RAW)==0) {
639 c &= 0177;
640 if (tp->t_state&TTSTOP) {
641 if (c==tun.t_startc) {
642 tp->t_state &= ~TTSTOP;
643 ttstart(tp);
644 return;
645 }
646 if (c==tun.t_stopc)
647 return;
648 tp->t_state &= ~TTSTOP;
649 ttstart(tp);
650 } else {
651 if (c==tun.t_stopc) {
652 tp->t_state |= TTSTOP;
653 (*cdevsw[major(tp->t_dev)].d_stop)(tp);
654 return;
655 }
656 if (c==tun.t_startc)
657 return;
658 }
659 if (c==tun.t_quitc || c==tun.t_intrc) {
07f8c7d2 660 flushtty(tp, FREAD|FWRITE);
89dc6dfb
BJ
661 c = (c==tun.t_intrc) ? SIGINT:SIGQUIT;
662 if (tp->t_chan)
663 scontrol(tp->t_chan, M_SIG, c);
664 else
8062c8a7 665 gsignal(tp->t_pgrp, c);
89dc6dfb
BJ
666 return;
667 }
668 if (c=='\r' && t_flags&CRMOD)
669 c = '\n';
670 }
671 if (tp->t_rawq.c_cc>TTYHOG) {
07f8c7d2 672 flushtty(tp, FREAD|FWRITE);
89dc6dfb
BJ
673 return;
674 }
675 if (t_flags&LCASE && c>='A' && c<='Z')
676 c += 'a'-'A';
101ba270 677 (void) putc(c, &tp->t_rawq);
89dc6dfb
BJ
678 if (t_flags&(RAW|CBREAK)||(c=='\n'||c==tun.t_eofc||c==tun.t_brkc)) {
679 if ((t_flags&(RAW|CBREAK))==0 && putc(0377, &tp->t_rawq)==0)
680 tp->t_delct++;
681 if ((cp=tp->t_chan)!=NULL)
101ba270 682 (void) sdata(cp); else
89dc6dfb
BJ
683 wakeup((caddr_t)&tp->t_rawq);
684 }
685 if (t_flags&ECHO) {
686 ttyoutput(c, tp);
687 if (c==tp->t_kill && (t_flags&(RAW|CBREAK))==0)
688 ttyoutput('\n', tp);
689 ttstart(tp);
690 }
691}
692
693
694/*
695 * Send stop character on input overflow.
696 */
697ttyblock(tp)
698register struct tty *tp;
699{
700 register x;
701 x = q1.c_cc + q2.c_cc;
702 if (q1.c_cc > TTYHOG) {
07f8c7d2 703 flushtty(tp, FREAD|FWRITE);
89dc6dfb
BJ
704 tp->t_state &= ~TBLOCK;
705 }
706 if (x >= TTYHOG/2) {
707 if (putc(tun.t_stopc, &tp->t_outq)==0) {
708 tp->t_state |= TBLOCK;
709 tp->t_char++;
710 ttstart(tp);
711 }
712 }
713}
714
715/*
716 * put character on TTY output queue, adding delays,
717 * expanding tabs, and handling the CR/NL bit.
718 * It is called both from the top half for output, and from
719 * interrupt level for echoing.
720 * The arguments are the character and the tty structure.
721 */
722ttyoutput(c, tp)
723register c;
724register struct tty *tp;
725{
726 register char *colp;
727 register ctype;
728
89dc6dfb
BJ
729 /*
730 * Ignore EOT in normal mode to avoid hanging up
731 * certain terminals.
732 * In raw mode dump the char unchanged.
733 */
89dc6dfb
BJ
734 if ((tp->t_flags&RAW)==0) {
735 c &= 0177;
736 if ((tp->t_flags&CBREAK)==0 && c==CEOT)
737 return;
738 } else {
101ba270
BJ
739 tk_nout++;
740 (void) putc(c, &tp->t_outq);
89dc6dfb
BJ
741 return;
742 }
743
744 /*
745 * Turn tabs to spaces as required
746 */
747 if (c=='\t' && (tp->t_flags&TBDELAY)==XTABS) {
101ba270
BJ
748 c = 8 - (tp->t_col & 7);
749 (void) b_to_q(" ", c, &tp->t_outq);
750 tp->t_col += c;
751 tk_nout += c;
89dc6dfb
BJ
752 return;
753 }
101ba270 754 tk_nout++;
89dc6dfb
BJ
755 /*
756 * for upper-case-only terminals,
757 * generate escapes.
758 */
759 if (tp->t_flags&LCASE) {
760 colp = "({)}!|^~'`";
761 while(*colp++)
762 if(c == *colp++) {
763 ttyoutput('\\', tp);
764 c = colp[-2];
765 break;
766 }
767 if ('a'<=c && c<='z')
768 c += 'A' - 'a';
769 }
770 /*
771 * turn <nl> to <cr><lf> if desired.
772 */
773 if (c=='\n' && tp->t_flags&CRMOD)
774 ttyoutput('\r', tp);
101ba270 775 (void) putc(c, &tp->t_outq);
89dc6dfb
BJ
776 /*
777 * Calculate delays.
778 * The numbers here represent clock ticks
779 * and are not necessarily optimal for all terminals.
780 * The delays are indicated by characters above 0200.
781 * In raw mode there are no delays and the
782 * transmission path is 8 bits wide.
783 */
784 colp = &tp->t_col;
785 ctype = partab[c];
786 c = 0;
787 switch (ctype&077) {
788
789 /* ordinary */
790 case 0:
791 (*colp)++;
792
793 /* non-printing */
794 case 1:
795 break;
796
797 /* backspace */
798 case 2:
799 if (*colp)
800 (*colp)--;
801 break;
802
803 /* newline */
804 case 3:
805 ctype = (tp->t_flags >> 8) & 03;
806 if(ctype == 1) { /* tty 37 */
807 if (*colp)
808 c = max(((unsigned)*colp>>4) + 3, (unsigned)6);
809 } else
810 if(ctype == 2) { /* vt05 */
811 c = 6;
812 }
813 *colp = 0;
814 break;
815
816 /* tab */
817 case 4:
818 ctype = (tp->t_flags >> 10) & 03;
819 if(ctype == 1) { /* tty 37 */
820 c = 1 - (*colp | ~07);
821 if(c < 5)
822 c = 0;
823 }
824 *colp |= 07;
825 (*colp)++;
826 break;
827
828 /* vertical motion */
829 case 5:
830 if(tp->t_flags & VTDELAY) /* tty 37 */
831 c = 0177;
832 break;
833
834 /* carriage return */
835 case 6:
836 ctype = (tp->t_flags >> 12) & 03;
837 if(ctype == 1) { /* tn 300 */
838 c = 5;
839 } else if(ctype == 2) { /* ti 700 */
840 c = 10;
841 } else if(ctype == 3) { /* concept 100 */
842 int i;
6109e54e
BJ
843 if ((i = *colp) >= 0)
844 for (; i<9; i++)
845 (void) putc(0177, &tp->t_outq);
89dc6dfb
BJ
846 }
847 *colp = 0;
848 }
849 if(c)
101ba270 850 (void) putc(c|0200, &tp->t_outq);
89dc6dfb
BJ
851}
852
853/*
854 * Restart typewriter output following a delay
855 * timeout.
856 * The name of the routine is passed to the timeout
857 * subroutine and it is called during a clock interrupt.
858 */
859ttrstrt(tp)
860register struct tty *tp;
861{
862
863 tp->t_state &= ~TIMEOUT;
864 ttstart(tp);
865}
866
867/*
868 * Start output on the typewriter. It is used from the top half
869 * after some characters have been put on the output queue,
870 * from the interrupt routine to transmit the next
871 * character, and after a timeout has finished.
872 */
873ttstart(tp)
874register struct tty *tp;
875{
876 register s;
877
878 s = spl5();
879 if((tp->t_state&(TIMEOUT|TTSTOP|BUSY)) == 0)
880 (*tp->t_oproc)(tp);
881 splx(s);
882}
883
884/*
885 * Called from device's read routine after it has
886 * calculated the tty-structure given as argument.
887 */
888ttread(tp)
889register struct tty *tp;
890{
891register s;
892
893 if ((tp->t_state&CARR_ON)==0)
894 return(-1);
895 s = spl5();
896 if (tp->t_canq.c_cc==0)
897 while (canon(tp)<0)
898 if (tp->t_chan==NULL) {
899 sleep((caddr_t)&tp->t_rawq, TTIPRI);
900 } else {
901 splx(s);
902 return(0);
903 }
904 splx(s);
905 while (tp->t_canq.c_cc && passc(getc(&tp->t_canq))>=0)
906 ;
907 return(tp->t_rawq.c_cc+tp->t_canq.c_cc);
908}
909
910/*
911 * Called from the device's write routine after it has
912 * calculated the tty-structure given as argument.
913 */
914caddr_t
915ttwrite(tp)
916register struct tty *tp;
917{
918 /*
919 * THE POSITIONING OF CP, CC, AND CE ARE CRITICAL
920 * AND MUST NOT BE CHANGED WITHOUT PATCHING
921 * THE 'ASM' INLINES BELOW. WATCH OUT.
922 */
923 register char *cp;
924 register int cc, ce;
925 register i;
926 char obuf[OBUFSIZ];
927
928 if ((tp->t_state&CARR_ON)==0)
929 return(NULL);
930 while (u.u_count) {
931 cc = MIN(u.u_count, OBUFSIZ);
932 cp = obuf;
933 iomove(cp, (unsigned)cc, B_WRITE);
934 if (u.u_error)
935 break;
101ba270 936 (void) spl5();
89dc6dfb
BJ
937 while (tp->t_outq.c_cc > TTHIWAT) {
938 ttstart(tp);
939 tp->t_state |= ASLEEP;
940 if (tp->t_chan) {
941 u.u_base -= cc;
942 u.u_offset -= cc;
943 u.u_count += cc;
101ba270 944 (void) spl0();
89dc6dfb
BJ
945 return((caddr_t)&tp->t_outq);
946 }
947 sleep((caddr_t)&tp->t_outq, TTOPRI);
948 }
101ba270 949 (void) spl0();
89dc6dfb
BJ
950 if (tp->t_flags&LCASE) {
951 while (cc--)
952 ttyoutput(*cp++,tp);
953 continue;
954 }
955 while (cc) {
956 if (tp->t_flags&RAW)
957 ce=cc;
958 else {
959#ifdef VAX
960 asm(" scanc r9,(r10),_partab,$077");
961 asm(" subl3 r0,r9,r8");
962#else
963 ce=0;
964 while(((partab[*(cp+ce)]&077)==0)&&(ce<cc))
965 ce++;
966#endif
967 if (ce==0) {
968 ttyoutput(*cp++,tp);
969 cc--;
101ba270 970 goto check;
89dc6dfb
BJ
971 }
972 }
973 i=b_to_q(cp,ce,&tp->t_outq);
974 ce-=i;
975 tk_nout+=ce;
976 tp->t_col+=ce;
977 cp+=ce;
978 cc-=ce;
101ba270
BJ
979check:
980 if (tp->t_outq.c_cc > TTHIWAT) {
981 (void) spl5();
89dc6dfb
BJ
982 while (tp->t_outq.c_cc > TTHIWAT) {
983 ttstart(tp);
984 tp->t_state |= ASLEEP;
985 sleep((caddr_t)&tp->t_outq, TTOPRI);
986 }
101ba270 987 (void) spl0();
89dc6dfb
BJ
988 }
989 }
990 }
991 ttstart(tp);
992 return(NULL);
993}