return in iodone
[unix-history] / usr / src / sys / kern / tty.c
CommitLineData
c392cc63 1/* tty.c 3.10 %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;
c392cc63
BJ
93 if (tp->t_line != OKILDISC)
94 tp->t_line = 0; /* conservative */
89dc6dfb
BJ
95}
96
89dc6dfb
BJ
97/*
98 * set default control characters.
99 */
100ttychars(tp)
101register struct tty *tp;
102{
8062c8a7 103
89dc6dfb
BJ
104 tun.t_intrc = CINTR;
105 tun.t_quitc = CQUIT;
106 tun.t_startc = CSTART;
107 tun.t_stopc = CSTOP;
108 tun.t_eofc = CEOT;
109 tun.t_brkc = CBRK;
110 tp->t_erase = CERASE;
111 tp->t_kill = CKILL;
8062c8a7 112/* begin local */
6fdc0335
BJ
113 tlun.t_suspc = CTRL(z);
114 tlun.t_dsuspc = CTRL(y);
8062c8a7
BJ
115 tlun.t_rprntc = CTRL(r);
116 tlun.t_flushc = CTRL(o);
117 tlun.t_werasc = CTRL(w);
118 tlun.t_lnextc = CTRL(v);
119 tlun.t_lintr = CTRL(c);
120 tlun.t_lerase = CTRL(h);
121 tlun.t_lkill = CTRL(u);
122 tp->t_local = 0;
123 tp->t_lstate = 0;
124/* end local */
89dc6dfb
BJ
125}
126
127/*
128 * clean tp on last close
129 */
130ttyclose(tp)
131register struct tty *tp;
132{
133
134 tp->t_pgrp = 0;
135 wflushtty(tp);
136 tp->t_state = 0;
c392cc63
BJ
137 if (tp->t_line != OKILDISC)
138 tp->t_line = 0;
89dc6dfb
BJ
139}
140
141/*
142 * stty/gtty writearound
143 */
144stty()
145{
146 u.u_arg[2] = u.u_arg[1];
147 u.u_arg[1] = TIOCSETP;
148 ioctl();
149}
150
151gtty()
152{
153 u.u_arg[2] = u.u_arg[1];
154 u.u_arg[1] = TIOCGETP;
155 ioctl();
156}
157
101ba270
BJ
158/*
159 * Do nothing specific version of line
160 * discipline specific ioctl command.
161 */
de857265 162/*ARGSUSED*/
101ba270
BJ
163nullioctl(tp, cmd, addr)
164register struct tty *tp;
165caddr_t addr;
166{
167
168 return (cmd);
169}
170
89dc6dfb
BJ
171/*
172 * ioctl system call
173 * Check legality, execute common code, and switch out to individual
174 * device routine.
175 */
176ioctl()
177{
178 register struct file *fp;
179 register struct inode *ip;
180 register struct a {
181 int fdes;
182 int cmd;
183 caddr_t cmarg;
184 } *uap;
185 register dev_t dev;
186 register fmt;
187
188 uap = (struct a *)u.u_ap;
189 if ((fp = getf(uap->fdes)) == NULL)
190 return;
191 if (uap->cmd==FIOCLEX) {
192 u.u_pofile[uap->fdes] |= EXCLOSE;
193 return;
194 }
195 if (uap->cmd==FIONCLEX) {
196 u.u_pofile[uap->fdes] &= ~EXCLOSE;
197 return;
198 }
199 ip = fp->f_inode;
200 fmt = ip->i_mode & IFMT;
201 if (fmt != IFCHR && fmt != IFMPC) {
8062c8a7
BJ
202/* begin local */
203 if (uap->cmd==FIONREAD && (fmt == IFREG || fmt == IFDIR)) {
204 off_t nread = ip->i_size - fp->f_un.f_offset;
205
206 if (copyout((caddr_t)&nread, uap->cmarg, sizeof(off_t)))
207 u.u_error = EFAULT;
208 } else
209/* end local */
210 u.u_error = ENOTTY;
89dc6dfb
BJ
211 return;
212 }
213 dev = ip->i_un.i_rdev;
214 u.u_r.r_val1 = 0;
215 (*cdevsw[major(dev)].d_ioctl)(dev, uap->cmd, uap->cmarg, fp->f_flag);
216}
217
218/*
219 * Common code for several tty ioctl commands
220 */
221ttioccomm(com, tp, addr, dev)
222register struct tty *tp;
223caddr_t addr;
224{
225 unsigned t;
8062c8a7 226 struct sgttyb iocb;
de857265 227 struct clist tq;
89dc6dfb
BJ
228 extern int nldisp;
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:
342 flushtty(tp);
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:
406 tp->t_pgrp = (int)addr;
407 break;
408
409 case TIOCGPGRP:
410 if (copyout((caddr_t)&tp->t_pgrp, addr, sizeof(tp->t_pgrp)))
411 u.u_error = EFAULT;
412 break;
413
414 /*
415 * Modify local mode word.
416 */
417 case TIOCLBIS:
418 tp->t_local |= (int)addr;
419 break;
420
421 case TIOCLBIC:
422 tp->t_local &= ~(int)addr;
423 break;
424
425 case TIOCLSET:
426 tp->t_local = (int)addr;
427 break;
428
429 case TIOCLGET:
430 if (copyout((caddr_t)&tp->t_local, addr, sizeof(tp->t_local)))
89dc6dfb
BJ
431 u.u_error = EFAULT;
432 break;
433
0dde1c43
BJ
434 case TIOCOUTQ:
435 if (copyout((caddr_t)&tp->t_outq.c_cc, addr, sizeof(tp->t_outq.c_cc)))
436 u.u_error = EFAULT;
437 break;
438
8062c8a7 439/* end of locals */
89dc6dfb
BJ
440 default:
441 return(0);
442 }
443 return(1);
444}
445
446/*
447 * Wait for output to drain, then flush input waiting.
448 */
449wflushtty(tp)
450register struct tty *tp;
451{
452
101ba270 453 (void) spl5();
89dc6dfb
BJ
454 while (tp->t_outq.c_cc && tp->t_state&CARR_ON) {
455 (*tp->t_oproc)(tp);
456 tp->t_state |= ASLEEP;
457 sleep((caddr_t)&tp->t_outq, TTOPRI);
458 }
459 flushtty(tp);
101ba270 460 (void) spl0();
89dc6dfb
BJ
461}
462
463/*
464 * flush all TTY queues
465 */
466flushtty(tp)
467register struct tty *tp;
468{
469 register s;
470
d1778415
BJ
471 if (tp->t_line == NETLDISC)
472 return;
101ba270 473 s = spl6();
89dc6dfb
BJ
474 while (getc(&tp->t_canq) >= 0)
475 ;
476 wakeup((caddr_t)&tp->t_rawq);
477 wakeup((caddr_t)&tp->t_outq);
89dc6dfb
BJ
478 tp->t_state &= ~TTSTOP;
479 (*cdevsw[major(tp->t_dev)].d_stop)(tp);
480 while (getc(&tp->t_outq) >= 0)
481 ;
482 while (getc(&tp->t_rawq) >= 0)
483 ;
484 tp->t_delct = 0;
8062c8a7 485 tp->t_rocount = 0; /* local */
6fdc0335 486 tp->t_lstate = 0;
89dc6dfb
BJ
487 splx(s);
488}
489
490
491
492/*
493 * transfer raw input list to canonical list,
494 * doing erase-kill processing and handling escapes.
495 * It waits until a full line has been typed in cooked mode,
496 * or until any character has been typed in raw mode.
497 */
498canon(tp)
499register struct tty *tp;
500{
501 register char *bp;
502 char *bp1;
503 register int c;
504 int mc;
505 int s;
506
507 if ((tp->t_flags&(RAW|CBREAK))==0 && tp->t_delct==0
508 || (tp->t_flags&(RAW|CBREAK))!=0 && tp->t_rawq.c_cc==0) {
509 return(-1);
510 }
511 s = spl0();
512loop:
513 bp = &canonb[2];
514 while ((c=getc(&tp->t_rawq)) >= 0) {
515 if ((tp->t_flags&(RAW|CBREAK))==0) {
516 if (c==0377) {
517 tp->t_delct--;
518 break;
519 }
520 if (bp[-1]!='\\') {
521 if (c==tp->t_erase) {
522 if (bp > &canonb[2])
523 bp--;
524 continue;
525 }
526 if (c==tp->t_kill)
527 goto loop;
528 if (c==tun.t_eofc)
529 continue;
530 } else {
531 mc = maptab[c];
532 if (c==tp->t_erase || c==tp->t_kill)
533 mc = c;
534 if (mc && (mc==c || (tp->t_flags&LCASE))) {
535 if (bp[-2] != '\\')
536 c = mc;
537 bp--;
538 }
539 }
540 }
541 *bp++ = c;
542 if (bp>=canonb+CANBSIZ)
543 break;
544 }
545 bp1 = &canonb[2];
101ba270 546 (void) b_to_q(bp1, bp-bp1, &tp->t_canq);
89dc6dfb
BJ
547
548 if (tp->t_state&TBLOCK && tp->t_rawq.c_cc < TTYHOG/5) {
549 if (putc(tun.t_startc, &tp->t_outq)==0) {
550 tp->t_state &= ~TBLOCK;
551 ttstart(tp);
552 }
553 tp->t_char = 0;
554 }
555
556 splx(s);
557 return(0);
558}
559
560
561/*
562 * block transfer input handler.
563 */
564ttyrend(tp, pb, pe)
565register struct tty *tp;
566register char *pb, *pe;
567{
568 int tandem;
569
570 tandem = tp->t_flags&TANDEM;
571 if (tp->t_flags&RAW) {
101ba270 572 (void) b_to_q(pb, pe-pb, &tp->t_rawq);
89dc6dfb 573 if (tp->t_chan)
101ba270 574 (void) sdata(tp->t_chan); else
89dc6dfb
BJ
575 wakeup((caddr_t)&tp->t_rawq);
576 } else {
577 tp->t_flags &= ~TANDEM;
578 while (pb < pe)
579 ttyinput(*pb++, tp);
580 tp->t_flags |= tandem;
581 }
582 if (tandem)
583 ttyblock(tp);
584}
585
586/*
587 * Place a character on raw TTY input queue, putting in delimiters
588 * and waking up top half as needed.
589 * Also echo if required.
590 * The arguments are the character and the appropriate
591 * tty structure.
592 */
593ttyinput(c, tp)
594register c;
595register struct tty *tp;
596{
597 register int t_flags;
598 register struct chan *cp;
599
600 tk_nin += 1;
601 c &= 0377;
602 t_flags = tp->t_flags;
603 if (t_flags&TANDEM)
604 ttyblock(tp);
605 if ((t_flags&RAW)==0) {
606 c &= 0177;
607 if (tp->t_state&TTSTOP) {
608 if (c==tun.t_startc) {
609 tp->t_state &= ~TTSTOP;
610 ttstart(tp);
611 return;
612 }
613 if (c==tun.t_stopc)
614 return;
615 tp->t_state &= ~TTSTOP;
616 ttstart(tp);
617 } else {
618 if (c==tun.t_stopc) {
619 tp->t_state |= TTSTOP;
620 (*cdevsw[major(tp->t_dev)].d_stop)(tp);
621 return;
622 }
623 if (c==tun.t_startc)
624 return;
625 }
626 if (c==tun.t_quitc || c==tun.t_intrc) {
627 flushtty(tp);
628 c = (c==tun.t_intrc) ? SIGINT:SIGQUIT;
629 if (tp->t_chan)
630 scontrol(tp->t_chan, M_SIG, c);
631 else
8062c8a7 632 gsignal(tp->t_pgrp, c);
89dc6dfb
BJ
633 return;
634 }
635 if (c=='\r' && t_flags&CRMOD)
636 c = '\n';
637 }
638 if (tp->t_rawq.c_cc>TTYHOG) {
639 flushtty(tp);
640 return;
641 }
642 if (t_flags&LCASE && c>='A' && c<='Z')
643 c += 'a'-'A';
101ba270 644 (void) putc(c, &tp->t_rawq);
89dc6dfb
BJ
645 if (t_flags&(RAW|CBREAK)||(c=='\n'||c==tun.t_eofc||c==tun.t_brkc)) {
646 if ((t_flags&(RAW|CBREAK))==0 && putc(0377, &tp->t_rawq)==0)
647 tp->t_delct++;
648 if ((cp=tp->t_chan)!=NULL)
101ba270 649 (void) sdata(cp); else
89dc6dfb
BJ
650 wakeup((caddr_t)&tp->t_rawq);
651 }
652 if (t_flags&ECHO) {
653 ttyoutput(c, tp);
654 if (c==tp->t_kill && (t_flags&(RAW|CBREAK))==0)
655 ttyoutput('\n', tp);
656 ttstart(tp);
657 }
658}
659
660
661/*
662 * Send stop character on input overflow.
663 */
664ttyblock(tp)
665register struct tty *tp;
666{
667 register x;
668 x = q1.c_cc + q2.c_cc;
669 if (q1.c_cc > TTYHOG) {
670 flushtty(tp);
671 tp->t_state &= ~TBLOCK;
672 }
673 if (x >= TTYHOG/2) {
674 if (putc(tun.t_stopc, &tp->t_outq)==0) {
675 tp->t_state |= TBLOCK;
676 tp->t_char++;
677 ttstart(tp);
678 }
679 }
680}
681
682/*
683 * put character on TTY output queue, adding delays,
684 * expanding tabs, and handling the CR/NL bit.
685 * It is called both from the top half for output, and from
686 * interrupt level for echoing.
687 * The arguments are the character and the tty structure.
688 */
689ttyoutput(c, tp)
690register c;
691register struct tty *tp;
692{
693 register char *colp;
694 register ctype;
695
89dc6dfb
BJ
696 /*
697 * Ignore EOT in normal mode to avoid hanging up
698 * certain terminals.
699 * In raw mode dump the char unchanged.
700 */
89dc6dfb
BJ
701 if ((tp->t_flags&RAW)==0) {
702 c &= 0177;
703 if ((tp->t_flags&CBREAK)==0 && c==CEOT)
704 return;
705 } else {
101ba270
BJ
706 tk_nout++;
707 (void) putc(c, &tp->t_outq);
89dc6dfb
BJ
708 return;
709 }
710
711 /*
712 * Turn tabs to spaces as required
713 */
714 if (c=='\t' && (tp->t_flags&TBDELAY)==XTABS) {
101ba270
BJ
715 c = 8 - (tp->t_col & 7);
716 (void) b_to_q(" ", c, &tp->t_outq);
717 tp->t_col += c;
718 tk_nout += c;
89dc6dfb
BJ
719 return;
720 }
101ba270 721 tk_nout++;
89dc6dfb
BJ
722 /*
723 * for upper-case-only terminals,
724 * generate escapes.
725 */
726 if (tp->t_flags&LCASE) {
727 colp = "({)}!|^~'`";
728 while(*colp++)
729 if(c == *colp++) {
730 ttyoutput('\\', tp);
731 c = colp[-2];
732 break;
733 }
734 if ('a'<=c && c<='z')
735 c += 'A' - 'a';
736 }
737 /*
738 * turn <nl> to <cr><lf> if desired.
739 */
740 if (c=='\n' && tp->t_flags&CRMOD)
741 ttyoutput('\r', tp);
101ba270 742 (void) putc(c, &tp->t_outq);
89dc6dfb
BJ
743 /*
744 * Calculate delays.
745 * The numbers here represent clock ticks
746 * and are not necessarily optimal for all terminals.
747 * The delays are indicated by characters above 0200.
748 * In raw mode there are no delays and the
749 * transmission path is 8 bits wide.
750 */
751 colp = &tp->t_col;
752 ctype = partab[c];
753 c = 0;
754 switch (ctype&077) {
755
756 /* ordinary */
757 case 0:
758 (*colp)++;
759
760 /* non-printing */
761 case 1:
762 break;
763
764 /* backspace */
765 case 2:
766 if (*colp)
767 (*colp)--;
768 break;
769
770 /* newline */
771 case 3:
772 ctype = (tp->t_flags >> 8) & 03;
773 if(ctype == 1) { /* tty 37 */
774 if (*colp)
775 c = max(((unsigned)*colp>>4) + 3, (unsigned)6);
776 } else
777 if(ctype == 2) { /* vt05 */
778 c = 6;
779 }
780 *colp = 0;
781 break;
782
783 /* tab */
784 case 4:
785 ctype = (tp->t_flags >> 10) & 03;
786 if(ctype == 1) { /* tty 37 */
787 c = 1 - (*colp | ~07);
788 if(c < 5)
789 c = 0;
790 }
791 *colp |= 07;
792 (*colp)++;
793 break;
794
795 /* vertical motion */
796 case 5:
797 if(tp->t_flags & VTDELAY) /* tty 37 */
798 c = 0177;
799 break;
800
801 /* carriage return */
802 case 6:
803 ctype = (tp->t_flags >> 12) & 03;
804 if(ctype == 1) { /* tn 300 */
805 c = 5;
806 } else if(ctype == 2) { /* ti 700 */
807 c = 10;
808 } else if(ctype == 3) { /* concept 100 */
809 int i;
810 for (i= *colp; i<9; i++)
101ba270 811 (void) putc(0177, &tp->t_outq);
89dc6dfb
BJ
812 }
813 *colp = 0;
814 }
815 if(c)
101ba270 816 (void) putc(c|0200, &tp->t_outq);
89dc6dfb
BJ
817}
818
819/*
820 * Restart typewriter output following a delay
821 * timeout.
822 * The name of the routine is passed to the timeout
823 * subroutine and it is called during a clock interrupt.
824 */
825ttrstrt(tp)
826register struct tty *tp;
827{
828
829 tp->t_state &= ~TIMEOUT;
830 ttstart(tp);
831}
832
833/*
834 * Start output on the typewriter. It is used from the top half
835 * after some characters have been put on the output queue,
836 * from the interrupt routine to transmit the next
837 * character, and after a timeout has finished.
838 */
839ttstart(tp)
840register struct tty *tp;
841{
842 register s;
843
844 s = spl5();
845 if((tp->t_state&(TIMEOUT|TTSTOP|BUSY)) == 0)
846 (*tp->t_oproc)(tp);
847 splx(s);
848}
849
850/*
851 * Called from device's read routine after it has
852 * calculated the tty-structure given as argument.
853 */
854ttread(tp)
855register struct tty *tp;
856{
857register s;
858
859 if ((tp->t_state&CARR_ON)==0)
860 return(-1);
861 s = spl5();
862 if (tp->t_canq.c_cc==0)
863 while (canon(tp)<0)
864 if (tp->t_chan==NULL) {
865 sleep((caddr_t)&tp->t_rawq, TTIPRI);
866 } else {
867 splx(s);
868 return(0);
869 }
870 splx(s);
871 while (tp->t_canq.c_cc && passc(getc(&tp->t_canq))>=0)
872 ;
873 return(tp->t_rawq.c_cc+tp->t_canq.c_cc);
874}
875
876/*
877 * Called from the device's write routine after it has
878 * calculated the tty-structure given as argument.
879 */
880caddr_t
881ttwrite(tp)
882register struct tty *tp;
883{
884 /*
885 * THE POSITIONING OF CP, CC, AND CE ARE CRITICAL
886 * AND MUST NOT BE CHANGED WITHOUT PATCHING
887 * THE 'ASM' INLINES BELOW. WATCH OUT.
888 */
889 register char *cp;
890 register int cc, ce;
891 register i;
892 char obuf[OBUFSIZ];
893
894 if ((tp->t_state&CARR_ON)==0)
895 return(NULL);
896 while (u.u_count) {
897 cc = MIN(u.u_count, OBUFSIZ);
898 cp = obuf;
899 iomove(cp, (unsigned)cc, B_WRITE);
900 if (u.u_error)
901 break;
101ba270 902 (void) spl5();
89dc6dfb
BJ
903 while (tp->t_outq.c_cc > TTHIWAT) {
904 ttstart(tp);
905 tp->t_state |= ASLEEP;
906 if (tp->t_chan) {
907 u.u_base -= cc;
908 u.u_offset -= cc;
909 u.u_count += cc;
101ba270 910 (void) spl0();
89dc6dfb
BJ
911 return((caddr_t)&tp->t_outq);
912 }
913 sleep((caddr_t)&tp->t_outq, TTOPRI);
914 }
101ba270 915 (void) spl0();
89dc6dfb
BJ
916 if (tp->t_flags&LCASE) {
917 while (cc--)
918 ttyoutput(*cp++,tp);
919 continue;
920 }
921 while (cc) {
922 if (tp->t_flags&RAW)
923 ce=cc;
924 else {
925#ifdef VAX
926 asm(" scanc r9,(r10),_partab,$077");
927 asm(" subl3 r0,r9,r8");
928#else
929 ce=0;
930 while(((partab[*(cp+ce)]&077)==0)&&(ce<cc))
931 ce++;
932#endif
933 if (ce==0) {
934 ttyoutput(*cp++,tp);
935 cc--;
101ba270 936 goto check;
89dc6dfb
BJ
937 }
938 }
939 i=b_to_q(cp,ce,&tp->t_outq);
940 ce-=i;
941 tk_nout+=ce;
942 tp->t_col+=ce;
943 cp+=ce;
944 cc-=ce;
101ba270
BJ
945check:
946 if (tp->t_outq.c_cc > TTHIWAT) {
947 (void) spl5();
89dc6dfb
BJ
948 while (tp->t_outq.c_cc > TTHIWAT) {
949 ttstart(tp);
950 tp->t_state |= ASLEEP;
951 sleep((caddr_t)&tp->t_outq, TTOPRI);
952 }
101ba270 953 (void) spl0();
89dc6dfb
BJ
954 }
955 }
956 }
957 ttstart(tp);
958 return(NULL);
959}