home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Usenet 1994 October
/
usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso
/
misc
/
volume32
/
pol
/
part01
/
pty.c
< prev
next >
Wrap
C/C++ Source or Header
|
1992-10-18
|
10KB
|
532 lines
/*
* pty.c - Berkeley style pseudo tty driver for system V
*
* 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 TTI /* comment this define out for the original
* posted code
*/
#ifndef TTI
/*
* the following are arbitrary 3 unused bits from t_state
* in sys/tty.h
*/
#endif TTI
#ifndef TTI
#define MRWAIT 01000000 /* master waiting in read */
#else TTI
#define MRWAIT 01 /* master waiting in read */
#endif TTI
#define t_rloc t_cc[0] /* rchannel */
#ifndef TTI
#define MWWAIT 02000000 /* master waiting in write */
#else TTI
#define MWWAIT 02 /* master waiting in write */
#endif TTI
#define t_wloc t_cc[1] /* wchannel */
#ifndef TTI
#define MOPEN 04000000 /* master is open */
#else TTI
#define MOPEN 04 /* master is open */
#endif TTI
#include "sys/param.h"
#include "sys/types.h"
#include "sys/sysmacros.h"
#include "sys/seg.h"
#include "sys/page.h"
#include "sys/systm.h"
#include "sys/file.h"
#include "sys/conf.h"
#ifndef tower
#ifdef TTI
#include "sys/immu.h"
#endif TTI
#include "sys/region.h"
#endif
#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"
/*
* from config
*/
extern struct tty pts_tty[];
#ifdef TTI
extern int pts_state[];
#endif TTI
extern int pts_cnt;
int ptsflush = 0;
/*
* slave side is a fairly standard system V tty driver
*/
#ifndef TTI
ptsopen(dev, flag)
#else TTI
ptsopen(fdev, flag)
#endif TTI
{
#ifdef TTI
register dev = minor(fdev);
#endif 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
*/
#ifndef TTI
if (tp->t_state & MOPEN)
#else TTI
if (pts_state[dev] & MOPEN)
#endif 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);
}
#ifndef TTI
ptswrite(dev)
#else TTI
ptswrite(fdev)
#endif TTI
{
#ifdef TTI
register dev = minor(fdev);
#endif TTI
register struct tty *tp = &pts_tty[dev];
#ifdef TTI
#ifdef DEBUG
printf("T_TIME\n");
#endif
#endif TTI
(*linesw[tp->t_line].l_write)(tp);
}
#ifndef TTI
ptsread(dev)
#else TTI
ptsread(fdev)
#endif TTI
{
#ifdef TTI
register dev = minor(fdev);
#endif TTI
register struct tty *tp = &pts_tty[dev];
(*linesw[tp->t_line].l_read)(tp);
}
#ifndef TTI
ptsclose(dev)
#else TTI
ptsclose(fdev)
#endif TTI
{
#ifdef TTI
register dev = minor(fdev);
#endif TTI
register struct tty *tp = &pts_tty[dev];
(*linesw[tp->t_line].l_close)(tp);
tp->t_state &= ~CARR_ON;
}
#ifndef TTI
ptsioctl(dev, cmd, arg, mode)
#else TTI
ptsioctl(fdev, cmd, arg, mode)
#endif TTI
{
#ifdef TTI
register dev = minor(fdev);
#endif TTI
register struct tty *tp = &pts_tty[dev];
/* the driver hung on TCSETAF/W, so I have to do it myself, bjm */
if (cmd == TCSETAW || cmd == TCSETAF)
{
ptsflush++;
while ( tp->t_tbuf.c_ptr != NULL && tp->t_tbuf.c_count != 0 &&
tp->t_outq.c_cc != 0)
sleep((caddr_t *)&ptsflush, PSLEP);
if (cmd == TCSETAF)
ttyflush(tp, FREAD);
cmd = TCSETA;
ptsflush--;
}
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");
#endif
tp->t_state &= ~TIMEOUT;
goto start;
case T_WFLUSH:
#ifdef DEBUG
printf("T_WFLUSH\n");
#endif
tp->t_tbuf.c_size -= tp->t_tbuf.c_count;
tp->t_tbuf.c_count = 0;
if (ptsflush)
wakeup((caddr_t)&ptsflush);
/* fall through */
case T_RESUME:
#ifdef DEBUG
printf("T_RESUME\n");
#endif
tp->t_state &= ~TTSTOP;
/* fall through */
case T_OUTPUT:
#ifdef DEBUG
printf("T_OUTPUT\n");
#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;
}
#ifndef TTI
if (tbuf->c_count && (tp->t_state & MRWAIT)) {
tp->t_state &= ~MRWAIT;
#else TTI
if (tbuf->c_count && (pts_state[tp-pts_tty] & MRWAIT)) {
pts_state[tp-pts_tty] &= ~MRWAIT;
#endif TTI
wakeup((caddr_t)&tp->t_rloc);
}
break;
case T_SUSPEND:
#ifdef DEBUG
printf("T_SUSPEND\n");
#endif
tp->t_state |= TTSTOP;
break;
case T_BLOCK:
#ifdef DEBUG
printf("T_BLOCK\n");
#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");
#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");
#endif
#endif
case T_RFLUSH:
#ifdef DEBUG
printf("T_RFLUSH\n");
#endif
if (!(tp->t_state & TBLOCK))
break;
/* fall through */
case T_UNBLOCK:
#ifdef DEBUG
printf("T_UNBLOCK\n");
#endif
tp->t_state &= ~(TTXOFF|TBLOCK);
/* fall through */
case T_INPUT:
#ifdef DEBUG
printf("T_INPUT\n");
#endif
#ifndef TTI
if (tp->t_state & MWWAIT) {
tp->t_state &= ~MWWAIT;
#else TTI
if (pts_state[tp-pts_tty] & MWWAIT) {
pts_state[tp-pts_tty] &= ~MWWAIT;
#endif TTI
wakeup((caddr_t)&tp->t_wloc);
}
break;
#ifdef DEBUG
default:
printf("ptsproc: cmd %d\n",cmd);
#endif
}
}
/*
* master part - not actually like a tty
*/
#ifndef TTI
ptmopen(dev, flag)
#else TTI
ptmopen(fdev, flag)
#endif TTI
{
#ifdef TTI
register dev = minor(fdev);
#endif TTI
register struct tty *tp = &pts_tty[dev];
#ifdef DEBUG
printf("ptmopen(%d)\n",dev);
#endif
if (dev >= pts_cnt) {
u.u_error = ENXIO;
return;
}
/*
* allow only one controlling process
*/
#ifndef TTI
if (tp->t_state & MOPEN) {
#else TTI
if (pts_state[dev] & MOPEN) {
#endif TTI
u.u_error = EBUSY;
return;
}
if (tp->t_state & WOPEN)
wakeup((caddr_t)&tp->t_canq);
#ifndef TTI
tp->t_state |= CARR_ON|MOPEN;
#else TTI
tp->t_state |= CARR_ON;
pts_state[dev] |= MOPEN;
#endif TTI
}
#ifndef TTI
ptmread(dev)
#else TTI
ptmread(fdev)
#endif TTI
{
#ifdef TTI
register dev = minor(fdev);
#endif TTI
register struct tty *tp = &pts_tty[dev];
register n;
#ifndef TTI
if ((tp->t_state & ISOPEN) == 0) {
#else TTI
if ((tp->t_state & (ISOPEN|TTIOW)) == 0) {
#ifdef DEBUG
printf("ptmread(%d) EIO\n",dev);
#endif
#endif TTI
u.u_error = EIO;
return;
}
#ifdef DEBUG
printf("ptmread(%d)\n",dev);
#endif
#ifndef TTI
while (u.u_count) {
#else TTI
while (u.u_count>0) {
#endif 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;
#ifndef TTI
tp->t_state |= MRWAIT;
#else TTI
pts_state[dev] |= MRWAIT;
#endif 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;
if (ptsflush)
wakeup((caddr_t)&ptsflush);
break; /* bjm and jrm */
}
}
}
#ifndef TTI
ptmwrite(dev)
#else TTI
ptmwrite(fdev)
#endif TTI
{
#ifdef TTI
register dev = minor(fdev);
#endif 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);
#endif
#ifndef TTI
while (u.u_count) {
#else TTI
while (u.u_count>0) {
#endif TTI
if ((tp->t_state & TBLOCK) || tp->t_rbuf.c_ptr == NULL) {
if (u.u_fmode & FNDELAY)
break;
#ifndef TTI
tp->t_state |= MWWAIT;
#else TTI
pts_state[dev] |= MWWAIT;
#endif 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
/*
* 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
}
}
#ifndef TTI
ptmclose(dev)
#else TTI
ptmclose(fdev)
#endif TTI
{
#ifdef TTI
register dev = minor(fdev);
#endif TTI
register struct tty *tp = &pts_tty[dev];
#ifdef DEBUG
printf("ptmclose(%d)\n",dev);
#endif
if (tp->t_state & ISOPEN) {
signal(tp->t_pgrp, SIGHUP);
ttyflush(tp, FREAD|FWRITE);
}
/*
* virtual carrier gone
*/
#ifndef TTI
tp->t_state &= ~(CARR_ON|MOPEN);
#else TTI
tp->t_state &= ~CARR_ON;
pts_state[dev] &= ~MOPEN;
#endif TTI
}
#ifndef TTI
ptmioctl(dev, cmd, arg, mode)
#else TTI
ptmioctl(fdev, cmd, arg, mode)
#endif TTI
{
#ifdef TTI
register dev = minor(fdev);
#endif 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);
}
}
}