home *** CD-ROM | disk | FTP | other *** search
- /*
- * pty.c - Berkeley style pseudo tty driver for system V
- *
- * Additions marked:
- * TTI - for the changes made by Michael Bloom at Citicorp/TTI to make
- * it not Sperry 5000-series dependent. He did all the hard work.
- * The original code used some unused bits in the tty structure;
- * they turned out to be only unused in the Sperry/NCR Tower version.
- * He added the code to move the status bits out. He also added the
- * DEBUG code, which helped me to understand a little better how
- * the bytes flowed.
- * JRM - my unsubtle hacks to make it work with Microport.
- *
- * Other portions:
- * Copyright (c) 1987, Jens-Uwe Mager, FOCUS Computer GmbH
- * Not derived from licensed software.
- *
- * Permission is granted to freely use, copy, modify, and redistribute
- * this software, provided that no attempt is made to gain profit from it,
- * the author is not construed to be liable for any results of using the
- * software, alterations are clearly marked as such, and this notice is
- * not modified.
- */
- #define MAXPTYS 32
-
- /* TTI: */
- #define MRWAIT 01 /* master waiting in read */
- #define t_rloc t_cc[0] /* rchannel */
-
- #define MWWAIT 02 /* master waiting in write */
- #define t_wloc t_cc[1] /* wchannel */
-
- #define MOPEN 04 /* master is open */
- /* end TTI */
-
- #include "sys/param.h"
- #include "sys/types.h"
- #include "sys/sysmacros.h"
- #include "sys/seg.h"
- #include "sys/systm.h"
- #include "sys/file.h"
- #include "sys/conf.h"
-
- /* JRM: following removed
- #include "sys/page.h"
- #include "sys/immu.h"
- #include "sys/region.h"
- */
-
- #include "sys/proc.h"
- #include "sys/dir.h"
- #include "sys/tty.h"
- #include "sys/signal.h"
- #include "sys/user.h"
- #include "sys/errno.h"
- #include "sys/termio.h"
- #include "sys/ttold.h"
-
- /* JRM:
- * note: this is not subtle...if you know of a slick way to get this from
- * config, please tell me about it! */
- extern int pts_cnt;
- struct tty pts_tty[MAXPTYS];
- int pts_state[MAXPTYS];
-
- /*
- * slave side is a fairly standard system V tty driver
- */
- ptsopen(fdev, flag) /* TTI */
- {
- register dev = minor(fdev); /* TTI */
- register struct tty *tp = &pts_tty[dev];
- extern int ptsproc();
-
- if (dev >= pts_cnt) {
- u.u_error = ENXIO;
- return;
- }
- if ((tp->t_state & (ISOPEN|WOPEN)) == 0) {
- ttinit(tp);
- tp->t_proc = ptsproc;
- }
- /*
- * if master is still open, don't wait for carrier
- */
- if (pts_state[dev] & MOPEN) /* TTI */
- tp->t_state |= CARR_ON;
- if (!(flag & FNDELAY)) {
- while ((tp->t_state & CARR_ON) == 0) {
- tp->t_state |= WOPEN;
- sleep((caddr_t)&tp->t_canq, TTIPRI);
- }
- }
- (*linesw[tp->t_line].l_open)(tp);
- }
-
- ptswrite(fdev) /* TTI */
- {
- register dev = minor(fdev); /* TTI */
- register struct tty *tp = &pts_tty[dev];
-
- #ifdef DEBUG
- printf("T_TIME\n"); /* TTI */
- #endif DEBUG
- (*linesw[tp->t_line].l_write)(tp);
- }
-
- ptsread(fdev) /* TTI */
- {
- register dev = minor(fdev); /* TTI */
- register struct tty *tp = &pts_tty[dev];
-
- (*linesw[tp->t_line].l_read)(tp);
- }
-
- ptsclose(fdev) /* TTI */
- {
- register dev = minor(fdev); /* TTI */
- register struct tty *tp = &pts_tty[dev];
-
- (*linesw[tp->t_line].l_close)(tp);
- tp->t_state &= ~CARR_ON;
- }
-
- ptsioctl(fdev, cmd, arg, mode)
- {
- register dev = minor(fdev); /* TTI */
- register struct tty *tp = &pts_tty[dev];
-
- ttiocom(tp, cmd, arg, mode);
- }
-
- ptsproc(tp, cmd)
- register struct tty *tp;
- {
- register struct ccblock *tbuf;
- extern ttrstrt();
-
- switch (cmd) {
- case T_TIME:
- #ifdef DEBUG
- printf("T_TIME\n"); /* TTI */
- #endif
- tp->t_state &= ~TIMEOUT;
- goto start;
- case T_WFLUSH:
- #ifdef DEBUG
- printf("T_WFLUSH\n"); /* TTI */
- #endif
- tp->t_tbuf.c_size -= tp->t_tbuf.c_count;
- tp->t_tbuf.c_count = 0;
- /* fall through */
- case T_RESUME:
- #ifdef DEBUG
- printf("T_RESUME\n"); /* TTI */
- #endif
- tp->t_state &= ~TTSTOP;
- /* fall through */
- case T_OUTPUT:
- #ifdef DEBUG
- printf("T_OUTPUT\n"); /* TTI */
- #endif
- start:
- if (tp->t_state & (TTSTOP|TIMEOUT))
- break;
- tbuf = &tp->t_tbuf;
- if (tbuf->c_ptr == NULL || tbuf->c_count == 0) {
- if (tbuf->c_ptr)
- tbuf->c_ptr -= tbuf->c_size;
- if (!(CPRES & (*linesw[tp->t_line].l_output)(tp)))
- break;
- }
- if (tbuf->c_count && (pts_state[tp-pts_tty] & MRWAIT)) {
- pts_state[tp-pts_tty] &= ~MRWAIT; /* TTI */
- wakeup((caddr_t)&tp->t_rloc);
- }
- break;
- case T_SUSPEND:
- #ifdef DEBUG
- printf("T_SUSPEND\n"); /* TTI */
- #endif
- tp->t_state |= TTSTOP;
- break;
- case T_BLOCK:
- #ifdef DEBUG
- printf("T_BLOCK\n"); /* TTI */
- #endif
- /*
- * the check for ICANON appears to be neccessary
- * to avoid a hang when overflowing input
- */
- if ((tp->t_iflag & ICANON) == 0)
- tp->t_state |= TBLOCK;
- break;
- case T_BREAK:
- #ifdef DEBUG
- printf("T_BREAK\n"); /* TTI */
- #endif
- tp->t_state |= TIMEOUT;
- timeout(ttrstrt, tp, HZ/4);
- break;
- #ifdef T_LOG_FLUSH
- case T_LOG_FLUSH:
- #ifdef DEBUG
- printf("T_LOG_FLUSH\n"); /* TTI */
- #endif
- #endif
- case T_RFLUSH:
- #ifdef DEBUG
- printf("T_RFLUSH\n"); /* TTI */
- #endif
- if (!(tp->t_state & TBLOCK))
- break;
- /* fall through */
- case T_UNBLOCK:
- #ifdef DEBUG
- printf("T_UNBLOCK\n"); /* TTI */
- #endif
- tp->t_state &= ~(TTXOFF|TBLOCK);
- /* fall through */
- case T_INPUT:
- #ifdef DEBUG
- printf("T_INPUT\n"); /* TTI */
- #endif
- if (pts_state[tp-pts_tty] & MWWAIT) {
- pts_state[tp-pts_tty] &= ~MWWAIT; /* TTI */
- wakeup((caddr_t)&tp->t_wloc);
- }
- break;
- #ifdef DEBUG
- default: /* TTI */
- printf("ptsproc: cmd %d\n",cmd);
- #endif
- }
- }
-
- /*
- * master part - not actually like a tty
- */
-
- ptmopen(fdev, flag) /* TTI */
- {
- register dev = minor(fdev); /* TTI */
- register struct tty *tp = &pts_tty[dev];
-
- #ifdef DEBUG
- printf("ptmopen(%d)\n",dev); /* TTI */
- #endif
- if (dev >= pts_cnt) {
- u.u_error = ENXIO;
- return;
- }
- /*
- * allow only one controlling process
- */
- if (pts_state[dev] & MOPEN) { /* TTI */
- u.u_error = EBUSY;
- return;
- }
- if (tp->t_state & WOPEN)
- wakeup((caddr_t)&tp->t_canq);
- tp->t_state |= CARR_ON; /* TTI */
- pts_state[dev] |= MOPEN;
- }
-
- ptmread(fdev) /* TTI */
- {
- register dev = minor(fdev); /* TTI */
- register struct tty *tp = &pts_tty[dev];
- register n;
-
- if ((tp->t_state & (ISOPEN|TTIOW)) == 0) { /* TTI */
- #ifdef DEBUG
- printf("ptmread(%d) EIO\n",dev); /* TTI */
- #endif
- u.u_error = EIO;
- return;
- }
- #ifdef DEBUG
- printf("ptmread(%d)\n",dev); /* TTI */
- #endif
- while (u.u_count>0) { /* TTI */
- ptsproc(tp, T_OUTPUT);
- if ((tp->t_state & (TTSTOP|TIMEOUT))
- || tp->t_tbuf.c_ptr == NULL || tp->t_tbuf.c_count == 0) {
- if (u.u_fmode & FNDELAY)
- break;
- pts_state[dev] |= MRWAIT; /* TTI */
- sleep((caddr_t)&tp->t_rloc, TTIPRI);
- continue;
- }
- n = min(u.u_count, tp->t_tbuf.c_count);
- if (n) {
- if (copyout(tp->t_tbuf.c_ptr, u.u_base, n)) {
- u.u_error = EFAULT;
- break;
- }
- tp->t_tbuf.c_count -= n;
- tp->t_tbuf.c_ptr += n;
- u.u_base += n;
- u.u_count -= n;
- break; /* JRM: added - without this, the flow from
- slave to master is buffered */
- }
- }
- }
-
- ptmwrite(fdev) /* TTI */
- {
- register dev = minor(fdev); /* TTI */
- register struct tty *tp = &pts_tty[dev];
- register n;
-
- if ((tp->t_state & ISOPEN) == 0) {
- u.u_error = EIO;
- return;
- }
- #ifdef DEBUG
- printf("ptmwrite(%d)\n",dev); /* TTI */
- #endif
- while (u.u_count>0) { /* TTI */
- if ((tp->t_state & TBLOCK) || tp->t_rbuf.c_ptr == NULL) {
- if (u.u_fmode & FNDELAY)
- break;
- pts_state[dev] |= MWWAIT; /* TTI */
- sleep((caddr_t)&tp->t_wloc, TTOPRI);
- continue;
- }
- n = min(u.u_count, tp->t_rbuf.c_count);
- if (n) {
- if (copyin(u.u_base,tp->t_rbuf.c_ptr, n)) {
- u.u_error = EFAULT;
- break;
- }
- tp->t_rbuf.c_count -= n;
- u.u_base += n;
- u.u_count -= n;
- }
- #ifdef vax || m68k /* TTI */
- /*
- * somebody told me this is necessary on the vax
- */
- (*linesw[tp->t_line].l_input)(tp, L_BUF);
- #else
- (*linesw[tp->t_line].l_input)(tp);
- #endif
- }
- }
-
- ptmclose(fdev) /* TTI */
- {
- register dev = minor(fdev); /* TTI */
- register struct tty *tp = &pts_tty[dev];
-
- #ifdef DEBUG
- printf("ptmclose(%d)\n",dev); /* TTI */
- #endif
- if (tp->t_state & ISOPEN) {
- signal(tp->t_pgrp, SIGHUP);
- ttyflush(tp, FREAD|FWRITE);
- }
- /*
- * virtual carrier gone
- */
- tp->t_state &= ~CARR_ON; /* TTI */
- pts_state[dev] &= ~MOPEN;
- }
-
- ptmioctl(fdev, cmd, arg, mode) /* TTI */
- {
- register dev = minor(fdev); /* TTI */
- register struct tty *tp = &pts_tty[dev];
-
- /*
- * sorry, but we can't fiddle with the tty struct without
- * having done LDOPEN
- */
- if (tp->t_state & ISOPEN) {
- if (cmd == TCSBRK && arg == NULL) {
- signal(tp->t_pgrp, SIGINT);
- if ((tp->t_iflag & NOFLSH) == 0)
- ttyflush(tp, FREAD|FWRITE);
- } else {
- /*
- * we must flush output to avoid hang in ttywait
- */
- if (cmd == TCSETAW || cmd == TCSETAF || cmd == TCSBRK
- || cmd == TIOCSETP)
- ttyflush(FWRITE);
- ttiocom(tp, cmd, arg, mode);
- }
- }
- }
-