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