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