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