From uucp Wed Jan 17 01:38 EST 1990
>From ames!amix.commodore.com!ford  Wed Jan 17 01:38:12 1990 remote from icus
Received: by limbic.UUCP (smail2.5)
	id AA07620; 17 Jan 90 01:38:12 EST (Wed)
Received: by icus.islp.ny.us (smail2.5 <modified>)
	id AA10114; 17 Jan 90 00:42:04 EST (Wed)
Received: by icus.islp.ny.us (smail2.5 <modified>)
	id AA01433; 16 Jan 90 04:20:35 EST (Tue)
Received: from RUTGERS.EDU by ames.arc.nasa.gov (5.61/1.2); Mon, 15 Jan 90 23:29:41 -0800
Received: from cbmvax.UUCP by rutgers.edu (5.59/SMI4.0/RU1.3/3.05) with UUCP 
	id AA18895; Tue, 16 Jan 90 01:58:39 EST
Received: by cbmvax.cbm.commodore.com (5.57/UUCP-Project/Commodore Jan 13 1990)
	id AA01492; Mon, 15 Jan 90 23:01:17 EST
Received: by amix.commodore.com (/\=-/\ Smail3.1.17.5 #17.7)
	id <m0gnkNJ-0000FoC@amix.commodore.com>; Mon, 15 Jan 90 23:00 EST
Message-Id: <m0gnkNJ-0000FoC@amix.commodore.com>
Date: Mon, 15 Jan 90 23:00 EST
From: ford@amix.commodore.com (Mike "Ford" Ditto)
To: lenny@icus.islp.ny.us
Subject: pty driver (Re: Maximum allowed open windows on UNIXPC)
Newsgroups: unix-pc.general
In-Reply-To: <1067@icus.islp.ny.us>
References: <31@suntau.UUCP>
Organization: Commodore Amix Development
Status: RO


In article <1067@icus.islp.ny.us> you write:
>In article <31@suntau.UUCP> forrie@suntau.UUCP (Forrie Aldrich) writes:
>|>Also:  has anyone seen some recent updated version(s) of the PTY package for
>|>the 3b1... one that has all (or most) of the bugs weeded out?
>|>
>
>It's available on the ICUS Archives (see previous postings regarding access
>to that) in pty.shar.Z.  There are no _know_ bugs, at least as far as I know.

Although I sent this to Eric, I don't think it ever got posted.  Perhaps
it deserves a diff against the version you have.  I fixed several bugs.

					-=] Ford [=-

#! /bin/sh
# This is a shell archive, meaning:
# 1. Remove everything above the #! /bin/sh line.
# 2. Save the resulting text in a file.
# 3. Execute the file with /bin/sh (not csh) to create the files:
#	Files
#	INSTALL
#	Install
#	Makefile
#	Name
#	PTYCNT
#	README.3b1
#	READ_ME
#	Remove
#	Size
#	pty.c
# This archive created: Fri Mar  3 01:38:36 1989
export PATH; PATH=/bin:$PATH
echo shar: extracting "'Files'" '(52 characters)'
if test -f 'Files'
then
	echo shar: will not over-write existing file "'Files'"
else
cat << \SHAR_EOF > 'Files'
Size
Install
Name
Remove
Files
INSTALL
PTYCNT
pty.o
SHAR_EOF
if test 52 -ne "`wc -c < 'Files'`"
then
	echo shar: error transmitting "'Files'" '(should have been 52 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'INSTALL'" '(1582 characters)'
if test -f 'INSTALL'
then
	echo shar: will not over-write existing file "'INSTALL'"
else
cat << \SHAR_EOF > 'INSTALL'

MODULE=${1:-pty}
LETTER=${2:-p}
case "$LETTER" in
[a-zA-Z])
	:
	;;
*)
	echo "second arg must be single letter." 1>&2
	exit 1
	;;
esac

if [ ! -f pty.o ]
then
	echo "you must make pty.o before running INSTALL" 1>&2
	exit 1
fi


# NOTE!!!!!!!!!!!!!!
# To change the number of ptys, change the value in PTYCNT

PTYCNT=`sed -n 's/.*PTYCNT//p' PTYCNT`
MASTERMINOR=`sed -n 's/.*MASTERMINOR//p' PTYCNT`

/etc/masterupd -a -p pty char open release close read write ioctl ${MODULE}

# get the assigned device number
PTYMAJOR=`/etc/masterupd -c ${MODULE}`
if [ $? -ne 0 ]
then
	echo "${MODULE} cannot be added to the /etc/master file" 1>&2
	exit 1
fi


cp pty.o /etc/lddrv/${MODULE}.o

cd /etc/lddrv

# allocate and load the module

./lddrv -q ${MODULE} && ./lddrv -d ${MODULE}
./lddrv -a ${MODULE}
if [ $? -eq 0 ]
then
	echo "Driver ${MODULE} successfully loaded"
else
	echo "Error: Driver ${MODULE} failed loading stage" 1>&2
	exit 1
fi

# load the ${MODULE} at boot time

echo ${MODULE} >> drivers


# make the pty device files in /dev

cnt=0
while [ $cnt -lt $PTYCNT ]
do
	for y in 0 1 2 3 4 5 6 7 8 9 a b c d e f
	do
		i=$LETTER$y
		if [ $cnt -ge ${PTYCNT} ] 
		then 
			break
		fi

		[ -c /dev/pty$i ] && rm -f /dev/pty$i
		[ -c /dev/tty$i ] && rm -f /dev/tty$i

		/etc/mknod /dev/pty$i c ${PTYMAJOR} \
			`expr $cnt + $MASTERMINOR` &&
		/etc/mknod /dev/tty$i c ${PTYMAJOR} $cnt ||
		exit 1
		chmod 666 /dev/pty$i /dev/tty$i
		chown root /dev/pty$i /dev/tty$i
		chgrp root /dev/pty$i /dev/tty$i

		cnt=`expr $cnt + 1`
	done
	LETTER=`echo $LETTER | tr '[a-z][A-Y]' '[b-z][A-Z]'`
done


SHAR_EOF
if test 1582 -ne "`wc -c < 'INSTALL'`"
then
	echo shar: error transmitting "'INSTALL'" '(should have been 1582 characters)'
fi
chmod +x 'INSTALL'
fi # end of overwriting check
echo shar: extracting "'Install'" '(437 characters)'
if test -f 'Install'
then
	echo shar: will not over-write existing file "'Install'"
else
cat << \SHAR_EOF > 'Install'
# Eric H. Herrin II
# University of Kentucky Mathematical Sciences
# eric@ms.uky.edu, eric@ms.uky.csnet, !cbosgd!ukma!eric
#
# Install script for System V Pty driver

MODULE=pty

./INSTALL $MODULE || exit 1

cd /etc/lddrv

# put an entry in InstDrv for ${MODULE}
cat >> InstDrv << EOF
Name=Pseudo tty driver
File=${MODULE}
Comment=Pseudo tty devices /dev/ttyp0 through /dev/ttyqf
EOF


echo "Pseudo tty drivers are now installed"
exit 0
SHAR_EOF
if test 437 -ne "`wc -c < 'Install'`"
then
	echo shar: error transmitting "'Install'" '(should have been 437 characters)'
fi
chmod +x 'Install'
fi # end of overwriting check
echo shar: extracting "'Makefile'" '(362 characters)'
if test -f 'Makefile'
then
	echo shar: will not over-write existing file "'Makefile'"
else
cat << \SHAR_EOF > 'Makefile'
CFLAGS= -O -DLOADABLE ${DEFS}

.c.o:
	${CC} ${CFLAGS} -c $<

pty.o : pty.c PTYCNT

all : PTYS+IN

install : pty.o
	./INSTALL

installable : PTYS+IN

PTYS+IN : pty.o
	cpio -oBc < Files > PTYS+IN

floppy : PTYS+IN
	echo "Insert a formatted floppy disk and press return"; read foo
	dd if=PTYS+IN of=/dev/rfp021 bs=16384

clean :
	rm pty.o PTYS+IN

clobber : clean

SHAR_EOF
if test 362 -ne "`wc -c < 'Makefile'`"
then
	echo shar: error transmitting "'Makefile'" '(should have been 362 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'Name'" '(18 characters)'
if test -f 'Name'
then
	echo shar: will not over-write existing file "'Name'"
else
cat << \SHAR_EOF > 'Name'
Pseudo tty driver
SHAR_EOF
if test 18 -ne "`wc -c < 'Name'`"
then
	echo shar: error transmitting "'Name'" '(should have been 18 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'PTYCNT'" '(131 characters)'
if test -f 'PTYCNT'
then
	echo shar: will not over-write existing file "'PTYCNT'"
else
cat << \SHAR_EOF > 'PTYCNT'
/* be careful; this file is read and used by the INSTALL script */
#define PTYCNT 32
#define MASTERMINOR 128
#define MASTERBIT 128
SHAR_EOF
if test 131 -ne "`wc -c < 'PTYCNT'`"
then
	echo shar: error transmitting "'PTYCNT'" '(should have been 131 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'README.3b1'" '(6448 characters)'
if test -f 'README.3b1'
then
	echo shar: will not over-write existing file "'README.3b1'"
else
cat << \SHAR_EOF > 'README.3b1'
README: Eric H. Herrin II
	University of Kentucky Mathematical Sciences Laboratories
 	915 Patterson Office Tower
	University of Kentucky
	Lexington, KY 40506
	eric@ms.uky.edu, eric@ms.uky.csnet, !cbosgd!ukma!eric

	Also modified by:
	Mike "Ford" Ditto
	Chief Executive Hacker, Omnicron Data Systems
	P.O. Box 1721
	Bonita, CA 92002
	(619) 421-1055
	kenobi!ford@crash.CTS.COM, ...!crash!kenobi!ford


This directory contains the PD pty driver for System V, modified for
use with the AT&T UnixPC or Convergent Technologies Safari 4 computers,
running Version 3.51 of the UNIX System V OS (it may also work on
earlier versions, but I have no way of verifying this).  Anyone using
this driver should have no problems, but I will provide no support.
Questions should be sent to the above address, either with ground mail
or real (e-)mail.


This README is intended to mark the changes made to the PD pty driver to
satisfy the author's request.  It was not easy or feasible to clearly mark
every change in the code, thus it was decided that an explanation of the
procedure would probably be enough.  A brief introduction to UnixPC 
device drivers is followed by the list of changes made.  A couple of
hacks will also be explained.

NOTE: The #ifdef DEBUG statements use eprintf() instead of printf().
      This puts any messages into the queue of system errors of
      the error icon at the top of the console.


UnixPC device drivers:

	The UnixPC has a different kind of device driver from other 
System V machines.  They can be loaded while the machine is running or
at boot time, but are always linked into the OS while the kernel is
active.  However nice this may be, there ARE some problems.  

	1.  Loadable device drivers CANNOT communicate with one another.
	    That is, one driver cannot use a data structure defined in 
	    another driver.  
	2.  Conf.c doesn't exist, it is redone by the /etc/lddrv -av 
	    program and relinked into the kernel.  Thus, one can't
	    declare common structures this way.


Changes to the PD pty driver:

	The following changes (hacks?) were made to the PD pty driver for
the purpose of making it usable on the UnixPC.

	   Problem 1 & 2 influenced me to try to make a single driver
	   (there were two, ptm and pts).  How could one do this?
	   My solution (and I would be very interested if you can
	   think of a better one) was to create the slave devices
	   /dev/tty[p-z][0-f] with minor numbers 0-(PTSCNT/2-1) and
	   master devices /dev/pty[p-z][0-f] with minor numbers 
	   (PTSCNT/2)-(PTSCNT-1).  Major numbers of both types of devices
	   are the same. I can then simply define a macro to determine 
	   whether the dev_t passed to the driver was a slave or master 
	   pty.  Once determined, I can perform the appropriate duties.  
	   Also, it was more readable to merge the ptm and pts modules 
	   into a single set of pty[open, close, ioctl, read, write]
	   routines.  I added a release routine so that the kernel will
	   think the device has properly released if one deallocates
	   the driver.

Ford's changes:
	   Master devices now have minor numbers starting at MASTERMINOR
	   regardless of how many pty's are configured.  This allows PTYCNT
	   to be changed without having to re-mknod the devices.  Also, I
	   renamed PTSCNT to PTYCNT, since it really means the number of
	   pty device pairs rather than the number of slaves.

	   If any ptys are in use, the release routine now returns an EBUSY
	   error, rather than print "panic: page fault in kernel, press reset
	   button to reboot" :-).

	   Closes of master and slave devices are now synchronized properly
	   so that the master doesn't lose data when the slave has closed down,
	   and the slave side does not hang forever on a close when there is
	   buffered data and the master has already closed.

Making alterations to the number of ptys, etc.
	   The number of ptys is defined in the file PTYCNT.  This number
	   should not exceed MASTERMINOR, which should be defined as the
	   number of minor device numbers possible divided by two.  I.e. the
	   Unix PC can only have 256 minor devices for a major device, so this
	   would allow a maximum of 64 ptys.  It is currently defined at 32,
	   but I believe this is quite liberal.  It is possible to have more
	   than one pty driver installed, so it is possible to have as many
	   ptys as you would ever want.

Pty driver generation and installation procedure.
	   Put the number of ptys you want in the file PTYCNT.
	   Run "make".
	   When the make is successful, run "make install" as ROOT.

	   If you would like to make an installable file, run
	   "make installable".  The file will be called PTYS+IN.

	   If you would like to make an installable disk,
	   Insert a FORMATTED floppy diskette and type "make floppy"

	   If you would like to have more than PTYCNT ptys, the "INSTALL"
	   (not "Install") script can be run giving it two arguments, a
	   unique name that you would like the module to have instead of
	   "pty", and a letter instead of "p" to start nameing the devices
	   with.  For example:

		./INSTALL pty0 p
		./INSTALL pty1 t
		./INSTALL pty1 x

	   This will install three new devices in the kernel, each with
	   its own major number, and create appropriate devices in /dev.
	   The "pty0" module will have devices named "/dev/ttyp0" though
	   "/dev/ttysf", the "pty1" module will have devices named
	   "/dev/ttyt0" through "/dev/ttywf", etc.  If you use this
	   multiple driver method, some kernel memory will be used up
	   for each driver installed.  Also, running the INSTALL script
	   takes the place of running "make install" as directed above,
	   so don't do both.


Acknowledgement:  I realize the usage of a single major device number is
a severe hack, and I welcome any improvements/solutions.  I do not assume
any responsibility for the changes I have made, nor do I imply any 
liability on the part of the original author.  I include a complete set
of {Install, Remove, etc, etc} scripts so that binary floppies may be
made to be installed by the UnixPC user agent.  I do not assume any
responsibility for these either.

	    Eric H. Herrin II
	    University of Kentucky Mathematical Sciences Laboratories


	Note -- I totally re-arranged the Install script and many other
	things, so if something doesn't work, yell at me before yelling
	at the above named person.
					-=] Ford [=-
					kenobi!ford@crash.CTS.COM
SHAR_EOF
if test 6448 -ne "`wc -c < 'README.3b1'`"
then
	echo shar: error transmitting "'README.3b1'" '(should have been 6448 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'READ_ME'" '(1689 characters)'
if test -f 'READ_ME'
then
	echo shar: will not over-write existing file "'READ_ME'"
else
cat << \SHAR_EOF > 'READ_ME'
For the Unix PC, ignore this file, and instead read README.3b1.

This is a pseudo tty driver for system V machines. It works very
similar to ptys on BSD, for instance emacs works fine. To install this
driver you will need to modify your `master' and `dfile' file which
contains your driver specifications. As these vary from machine to machine,
you will have to look up in your manual how to do that. Here is an example
for a sperry s5050 alias ncr tower 32 :

Add the following two lines to the driver description section in master:
pts	0	237	244	pts	0	0	28	32	0	tty
ptm	0	37	344	ptm	0	0	29	0	0

This says there are max 32 pts devices at major number 28 having associated
tty structures and 0 ptm devices having major number 29 with no associated
data. The number of ptm devices is not configurable, as this depends on the
number of pts's.

The following two lines go in the dfile:
pts	0	0	0
ptm	0	0	0

Probably you will also want to increase the NCLIST parameter.

If your configuration procedure is different, you must change the shell
script mkpty, which is used to create the device nodes in /dev.

The ptm devices (/dev/pty[p-z][0-9a-f]) are the controlling ones, everything
written there will show up at the associated pts device
(/dev/tty[p-z][0-9a-f]), as well as erverything which is written on the pts
device will show up on the ptm device. The pts side will accept the usual
termio ioctl calls. The master side is a bit different, as ioctl calls which
normally wait for output to drain flush output. The reason for this funny
behaviour is that otherwise the master side will hang. Also the master side
may be opened only once, further open calls will result in an EBUSY error.
SHAR_EOF
if test 1689 -ne "`wc -c < 'READ_ME'`"
then
	echo shar: error transmitting "'READ_ME'" '(should have been 1689 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'Remove'" '(461 characters)'
if test -f 'Remove'
then
	echo shar: will not over-write existing file "'Remove'"
else
cat << \SHAR_EOF > 'Remove'
#
# Eric H. Herrin II
# University of Kentucky Mathematical Sciences
# eric@ms.uky.edu, eric@ms.uky.csnet, !cbosgd!ukma!eric
#
# Remove script for pty driver.

# remove the pty device files
/bin/rm -f /dev/[tp]ty[p-z][0-9a-f]


MODULE=pty

cd /etc/lddrv

./lddrv -d ${MODULE}
/bin/rm -f ${MODULE}.o ${MODULE} ifile.${MODULE}

/etc/masterupd -d ${MODULE}

/bin/ed - drivers << EOF
/^${MODULE}\$/d
w
EOF

/bin/ed - InstDrv << EOF
/File=${MODULE}\$/
-1,+1d
w
EOF

SHAR_EOF
if test 461 -ne "`wc -c < 'Remove'`"
then
	echo shar: error transmitting "'Remove'" '(should have been 461 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'Size'" '(3 characters)'
if test -f 'Size'
then
	echo shar: will not over-write existing file "'Size'"
else
cat << \SHAR_EOF > 'Size'
16
SHAR_EOF
if test 3 -ne "`wc -c < 'Size'`"
then
	echo shar: error transmitting "'Size'" '(should have been 3 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'pty.c'" '(11335 characters)'
if test -f 'pty.c'
then
	echo shar: will not over-write existing file "'pty.c'"
else
cat << \SHAR_EOF > 'pty.c'


/*
 * 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.
 */

/*
 * Modified for use on the UnixPC by:
 * Eric H. Herrin II
 * University of Kentucky Mathematical Sciences Laboratories
 * eric@ms.uky.edu, eric@ms.uky.csnet, !cbosgd!ukma!eric
 *
 * Further modified and improved by:
 * Mike "Ford" Ditto
 * Chief Executive Hacker, Omnicron Data Systems
 * ford@kenobi.commodore.com, ...!crash!kenobi!ford
 *
 * See README.3b1 for details of port and installation.
 *
 * Even further modified for SysVr3 by Ford.
 */

/*
 * Define "LOADABLE" if pty should be a Unix-PC-style loadable driver.
 * Define "SVR3" if on System V Release 3.
 */

/* The UnixPC does not have any extra bits in t_state, thus
 * we provide other means of storing the state.
 */
#define MRWAIT	0x01				/* master waiting in read */
#define t_rloc	t_cc[0]				/* wchannel for MRWAIT */
#define MWWAIT	0x02				/* master waiting in write */
#define t_wloc	t_cc[1]				/* wchannel for MWWAIT */
#define MOPEN	0x04				/* master is open */
#define SOPEN	0x08				/* slave is open */

#define KERNEL		1
#define defined_io	1

#include "sys/param.h"
#include "sys/types.h"
#include "sys/sysmacros.h"
#include "sys/systm.h"
#include "sys/file.h"
#include "sys/conf.h"
#ifdef SVR3
#include "sys/immu.h"
#include "sys/region.h"
#endif
#include "sys/proc.h"
#include "sys/tty.h"
#include "sys/signal.h"
#include "sys/dir.h"
#include "sys/user.h"
#include "sys/errno.h"
#include "sys/termio.h"
#include "sys/ttold.h"

#ifndef L_BUF
#define L_BUF 0			/* SVr3 needs this second arg to l_input, */
				/* for other systems, 0 shouldn't hurt. */
#endif

#include "PTYCNT"		/* find out about PTYCNT and MASTERMINOR */

/* PTYCNT is the maximum number of master/slave pairs that will work */
#ifndef PTYCNT
#define PTYCNT 32
#endif

/* MASTERMINOR is the lowest minor device number for master devices */
#ifndef MASTERMINOR
#define MASTERMINOR ((minor(0xFFFF)+1)/2)
#endif

/* This macro is true if the device number passed corresponds to */
/* the MASTER side of a pty */
#ifdef MASTERBIT
#define Master(dev)	((dev)&MASTERBIT)
#else
#define Master(dev)	(minor((dev)) >= MASTERMINOR)
#endif /* MASTERBIT */

/* The tty structures must be local to this driver, since there
 * is no conf.c
 */
struct tty pts_tty[PTYCNT];
int ptystate[PTYCNT];

int ptsproc();


ptyopen(dev, flag)
	dev_t		dev;
	int		flag;
{
	register struct tty *tp;

	dev = minor(dev);
	if (Master(dev)) {
#		ifdef DEBUG
		eprintf("open(master): \n");
#		endif
		dev -= MASTERMINOR;
		tp = &pts_tty[dev];
		if (dev >= PTYCNT) {
			u.u_error = ENXIO;
			return;
		}
		/*
		* allow only one controlling process
		*/
		if (ptystate[dev] & MOPEN) {
			u.u_error = EBUSY;
			return;
		}
		ptystate[dev] |= MOPEN;
		tp->t_state |= CARR_ON;
		if (tp->t_state & WOPEN)
		{
			tp->t_state &= ~WOPEN;
			wakeup((caddr_t)&tp->t_canq);
		}
	} else {
#		ifdef DEBUG
		eprintf("open(slave): \n");
#		endif
		tp = &pts_tty[dev];
		if (dev >= PTYCNT) {
			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 (!(flag & FNDELAY)) {
			while ((tp->t_state & CARR_ON) == 0) {
				/* eprintf("slave_open going to sleep!"); */
				tp->t_state |= WOPEN;
				if (sleep((caddr_t)&tp->t_canq, TTIPRI|PCATCH)) {
					tp->t_state &= ~WOPEN;
					wakeup((caddr_t)&tp->t_canq);
					/* eprintf("slave open: interrupted"); */
					u.u_error = EINTR;
					return;
				}
				/* eprintf("slave_open woke up! %x %x",
					tp->t_state, u.u_procp->p_sig); */
			}
		}
		ptystate[dev] |= SOPEN;
		(*linesw[tp->t_line].l_open)(tp);
	}
}

ptyclose(dev, flag)
	dev_t		dev;
	int		flag;
{
	register struct tty *tp;

	dev = minor(dev);
	if (Master(dev)) {
#		ifdef DEBUG
		eprintf("close(master): \n");
#		endif
		dev -= MASTERMINOR;
		tp = &pts_tty[dev];
		if (!(ptystate[dev] & SOPEN)) {
			tp->t_tbuf.c_size  -= tp->t_tbuf.c_count;
			tp->t_tbuf.c_count = 0;
			tp->t_rbuf.c_size  -= tp->t_rbuf.c_count;
			tp->t_rbuf.c_count = 0;
			(*linesw[tp->t_line].l_close)(tp);
		} else {
			signal(tp->t_pgrp, SIGHUP);
			ttyflush(tp, FREAD|FWRITE);
		}
		/*
		 * virtual carrier gone
		 */
		tp->t_state &= ~(CARR_ON);
		ptystate[dev] &= ~MOPEN;
	} else {
#		ifdef DEBUG
		eprintf("close(slave): \n");
#		endif
		tp = &pts_tty[dev];
		if (!(ptystate[dev] & MOPEN)) {
			tp->t_tbuf.c_size  -= tp->t_tbuf.c_count;
			tp->t_tbuf.c_count = 0;
			tp->t_rbuf.c_size  -= tp->t_rbuf.c_count;
			tp->t_rbuf.c_count = 0;
			(*linesw[tp->t_line].l_close)(tp);
		}
		ptystate[dev] &= ~SOPEN;
		if (ptystate[dev] & MRWAIT)
		{
			ptystate[dev] &= ~MRWAIT;
			wakeup((caddr_t)&tp->t_rloc);
		}
		if (ptystate[dev] & MWWAIT)
		{
			ptystate[dev] &= ~MRWAIT;
			wakeup((caddr_t)&tp->t_wloc);
		}
	}
}

ptyread(dev)
	dev_t		dev;
{
	register struct tty *tp;
	register n;

	dev = minor(dev);
	if (Master(dev)) {
		int didsome=0;
#		ifdef DEBUG
		eprintf("read(master): \n");
#		endif
		dev -= MASTERMINOR;
		tp = &pts_tty[dev];
		while (u.u_count) {
			ptsproc(tp, T_OUTPUT);
			if ((tp->t_state & (TTSTOP|TIMEOUT))
			    || tp->t_tbuf.c_ptr == NULL || tp->t_tbuf.c_count == 0) {
				if (didsome)
					break;
				if ((ptystate[dev] & SOPEN) == 0) {
					u.u_error = EIO;
					return;
				}
				if (u.u_fmode & FNDELAY)
					break;
#				ifdef DEBUG
				eprintf("read(master): master going to sleep\n");
#				endif
				ptystate[dev] |= MRWAIT;
				sleep((caddr_t)&tp->t_rloc, TTIPRI);
#				ifdef DEBUG
				eprintf("read(master): master woke up\n");
#				endif

				continue;
			}
			n = min(u.u_count, tp->t_tbuf.c_count);
			if (n) {
#				ifdef DEBUG
				eprintf("read(master): got some stuff\n");
#				endif
				++didsome;
				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;
			}
		}
	} else {
#		ifdef DEBUG
		eprintf("read(slave): \n");
#		endif
		tp = &pts_tty[dev];
#		ifdef DEBUG
		eprintf("read(slave): got some stuff\n");
#		endif
		(*linesw[tp->t_line].l_read)(tp);
	}
}

ptywrite(dev)
	dev_t		dev;
{
	register struct tty *tp;
	register n;

	dev = minor(dev);
	if (Master(dev)) {
#		ifdef DEBUG
		eprintf("write(master): \n");
#		endif
		dev -= MASTERMINOR;
		tp = &pts_tty[dev];
		while (u.u_count) {
			if ((tp->t_state & TBLOCK)
			    || tp->t_rbuf.c_ptr == NULL) {
				if ((ptystate[dev] & SOPEN) == 0) {
					u.u_error = EIO;
					return;
				}
				if (u.u_fmode & FNDELAY)
					break;
				ptystate[dev] |= MWWAIT;
#				ifdef DEBUG
				eprintf("write(master): going to sleep\n");
#				endif

				sleep((caddr_t)&tp->t_wloc, TTOPRI);

#				ifdef DEBUG
				eprintf("write: waking up\n");
#				endif

				continue;
			}
			n = min(u.u_count, tp->t_rbuf.c_count);
			if (n) {
#				ifdef DEBUG
				eprintf("write(master): sending some stuff\n");
#				endif
				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;
			}
			(*linesw[tp->t_line].l_input)(tp, L_BUF);
		}
	} else {
#		ifdef DEBUG
		eprintf("write(slave): \n");
#		endif
		tp = &pts_tty[dev];
#		ifdef DEBUG
		eprintf("write(slave): sending some stuff\n");
#		endif
		(*linesw[tp->t_line].l_write)(tp);
	}
}

ptyioctl(dev, cmd, arg, mode)
	dev_t		dev;
	int		cmd, arg, mode;
{
	register struct tty *tp;

	dev = minor(dev);
	if (Master(dev)) {
#		ifdef DEBUG
		eprintf("ioctl(master): \n");
#		endif
		dev -= MASTERMINOR;
		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(tp, FWRITE);
				ttiocom(tp, cmd, arg, mode);
			}
		} else
			u.u_error = EINVAL;
	} else {
#		ifdef DEBUG
		eprintf("ioctl(slave): \n");
#		endif
		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
		eprintf("ptsproc: T_TIME:\n");
#		endif
		tp->t_state &= ~TIMEOUT;
		goto start;
	case T_WFLUSH:
#		ifdef DEBUG
		eprintf("ptsproc: T_WFLUSH:\n");
#		endif
		tp->t_tbuf.c_size  -= tp->t_tbuf.c_count;
		tp->t_tbuf.c_count = 0;
		/* fall through */
	case T_RESUME:
#		ifdef DEBUG
		eprintf("ptsproc: T_RESUME:\n");
#		endif
		tp->t_state &= ~TTSTOP;
		/* fall through */
	case T_OUTPUT:
start:
#		ifdef DEBUG
		eprintf("ptsproc: T_OUTPUT:\n");
#		endif
		if (tp->t_state & (TTSTOP|TIMEOUT))
			break;
#		ifdef DEBUG
		eprintf("ptsproc: T_OUTPUT: past(TTSTOP|TIMEOUT)");
#		endif
		tbuf = &tp->t_tbuf;
		if (tbuf->c_ptr == NULL || tbuf->c_count == 0) {
#		ifdef DEBUG
		eprintf("ptsproc: T_OUTPUT: tbuf empty, may break\n");
#		endif
			if (tbuf->c_ptr)
				tbuf->c_ptr -= tbuf->c_size;
			if (!(CPRES & (*linesw[tp->t_line].l_output)(tp)))
				break;
		}
		if (tbuf->c_count && (ptystate[tp-pts_tty] & MRWAIT)) {
#		ifdef DEBUG
		eprintf("ptsproc: T_OUTPUT: waking up master\n");
#		endif
			ptystate[tp-pts_tty] &= ~MRWAIT;
			wakeup((caddr_t)&tp->t_rloc);
		}
#		ifdef DEBUG
		eprintf("ptsproc: T_OUTPUT: leaving end\n");
#		endif
		break;
	case T_SUSPEND:
#		ifdef DEBUG
		eprintf("ptsproc: T_SUSPEND:\n");
#		endif
		tp->t_state |= TTSTOP;
		break;
	case T_BLOCK:
#		ifdef DEBUG
		eprintf("ptsproc: 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
		eprintf("ptsproc: T_BREAK:\n");
#		endif
		tp->t_state |= TIMEOUT;
		timeout(ttrstrt, tp, HZ/4);
		break;
#ifdef T_LOG_FLUSH
	case T_LOG_FLUSH:
#endif
	case T_RFLUSH:
#		ifdef DEBUG
		eprintf("ptsproc: T_RFLUSH:\n");
#		endif
		if (!(tp->t_state & TBLOCK))
			break;
		/* fall through */
	case T_UNBLOCK:
#		ifdef DEBUG
		eprintf("ptsproc: T_UNBLOCK:\n");
#		endif
		tp->t_state &= ~(TTXOFF|TBLOCK);
		/* fall through */
	case T_INPUT:
#		ifdef DEBUG
		eprintf("ptsproc: T_INPUT:\n");
#		endif
		if (ptystate[tp-pts_tty] & MWWAIT) {
			ptystate[tp-pts_tty] &= ~MWWAIT;
#			ifdef DEBUG
			eprintf("ptsproc: T_INPUT: waking up master\n");
#			endif
			wakeup((caddr_t)&tp->t_wloc);
		}
		break;
	default:
#		ifdef DEBUG
		eprintf("ptsproc: default:\n");
#		else
		;
#		endif
	}
}

#ifdef LOADABLE
ptyrelease()
{
	register i;
#	ifdef DEBUG
	eprintf("ptyrelease:\n");
#	endif
	for ( i=0 ; i<PTYCNT ; ++i )
		if ( (ptystate[i] & (SOPEN|MOPEN))
		   || (pts_tty[i].t_state & WOPEN) )
		{
			u.u_error = EBUSY;
			return;
		}
	return;
}
#endif /* LOADABLE */
SHAR_EOF
if test 11335 -ne "`wc -c < 'pty.c'`"
then
	echo shar: error transmitting "'pty.c'" '(should have been 11335 characters)'
fi
fi # end of overwriting check
#	End of shell archive
exit 0
---
					-=] Ford [=-

"A just machine to make big decisions	(In Real Life:  Mike Ditto)
programmed by fellows with compassion	ditto@amix.commodore.com
and vision." - Donald Fagen, "IGY"	uunet!cbmvax!ditto
					ford@kenobi.commodore.com



