mb@ttidca.TTI.COM (Michael Bloom) (02/22/88)
Index: Public Domain Pty Driver Bugs and Fixes Note: This is being cross posted to comp.emacs because of the usefulness of pty's to emacs. Please, no flames. Description: There were several problems with the previously posted public domain pty driver. First, it was trying to use "unused bits" in t_state. Unfortunately, the existence of these unused bits assumes that t_state is long. On most 5r3 systems (I don't know about 5r2), however, it is a short. Second, the driver was assuming that only the minor device gets passed. While perhaps true on the tower, this is again not true on other ports. (In fact it can be a *pain* on the tower if you have drivers that use extra major devices to simulate minors > 255). Finally, there was a bug in which a read on the master device could hang in ttywait. This would happen if the slave had written some data and then closed his side before the master could read it. The fix for this is in the beginning of ptmread. Repeat-by: Don't bother. The original code could not have worked at all on most systems. Fix: The changes I made to the original posted code are entirely within ifdefs. This clearly marks the changes I have made (so as to comply with the author's request to do so). Because of this, the diff file is a little bigger than the original (pretty small) source file. So instead of diffs, I'm sending out the replacement in it's entirety. Clip out the following shar file and run it through sh to get a replacement for pty.c. In conf.c, declate pts_state to have the same number of elements as pts_tty. pts_cnt should also be initialized to the same number. ------- CUT HERE ---- #! /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: # pty.c # This archive created: Sun Feb 21 16:43:44 1988 export PATH; PATH=/bin:/usr/bin:$PATH echo shar: "extracting 'pty.c'" '(9410 characters)' if test -f 'pty.c' then echo shar: "will not over-write existing file 'pty.c'" else sed 's/^ X//' << \SHAR_EOF > 'pty.c' X/* X * pty.c - Berkeley style pseudo tty driver for system V X * X * Copyright (c) 1987, Jens-Uwe Mager, FOCUS Computer GmbH X * Not derived from licensed software. X * X * Permission is granted to freely use, copy, modify, and redistribute X * this software, provided that no attempt is made to gain profit from it, X * the author is not construed to be liable for any results of using the X * software, alterations are clearly marked as such, and this notice is X * not modified. X */ X#define TTI /* comment this define out for the original X * posted code X */ X#ifndef TTI X/* X * the following are arbitrary 3 unused bits from t_state X * in sys/tty.h X */ X#endif TTI X X#ifndef TTI X#define MRWAIT 01000000 /* master waiting in read */ X#else TTI X#define MRWAIT 01 /* master waiting in read */ X#endif TTI X#define t_rloc t_cc[0] /* rchannel */ X X#ifndef TTI X#define MWWAIT 02000000 /* master waiting in write */ X#else TTI X#define MWWAIT 02 /* master waiting in write */ X#endif TTI X#define t_wloc t_cc[1] /* wchannel */ X X#ifndef TTI X#define MOPEN 04000000 /* master is open */ X#else TTI X#define MOPEN 04 /* master is open */ X#endif TTI X X#include "sys/param.h" X#include "sys/types.h" X#include "sys/sysmacros.h" X#include "sys/seg.h" X#include "sys/page.h" X#include "sys/systm.h" X#include "sys/file.h" X#include "sys/conf.h" X X#ifndef tower X#ifdef TTI X#include "sys/immu.h" X#endif TTI X#include "sys/region.h" X#endif X X#include "sys/proc.h" X#include "sys/dir.h" X#include "sys/tty.h" X#include "sys/signal.h" X#include "sys/user.h" X#include "sys/errno.h" X#include "sys/termio.h" X#include "sys/ttold.h" X X/* X * from config X */ Xextern struct tty pts_tty[]; X X#ifdef TTI Xextern int pts_state[]; X#endif TTI Xextern int pts_cnt; X X/* X * slave side is a fairly standard system V tty driver X */ X#ifndef TTI Xptsopen(dev, flag) X#else TTI Xptsopen(fdev, flag) X#endif TTI X{ X#ifdef TTI X register dev = minor(fdev); X#endif TTI X register struct tty *tp = &pts_tty[dev]; X extern int ptsproc(); X X if (dev >= pts_cnt) { X u.u_error = ENXIO; X return; X } X if ((tp->t_state & (ISOPEN|WOPEN)) == 0) { X ttinit(tp); X tp->t_proc = ptsproc; X } X /* X * if master is still open, don't wait for carrier X */ X#ifndef TTI X if (tp->t_state & MOPEN) X#else TTI X if (pts_state[dev] & MOPEN) X#endif TTI X tp->t_state |= CARR_ON; X if (!(flag & FNDELAY)) { X while ((tp->t_state & CARR_ON) == 0) { X tp->t_state |= WOPEN; X sleep((caddr_t)&tp->t_canq, TTIPRI); X } X } X (*linesw[tp->t_line].l_open)(tp); X} X X#ifndef TTI Xptswrite(dev) X#else TTI Xptswrite(fdev) X#endif TTI X{ X#ifdef TTI X register dev = minor(fdev); X#endif TTI X register struct tty *tp = &pts_tty[dev]; X X#ifdef TTI X#ifdef DEBUG X printf("T_TIME\n"); X#endif X X#endif TTI X (*linesw[tp->t_line].l_write)(tp); X} X X#ifndef TTI Xptsread(dev) X#else TTI Xptsread(fdev) X#endif TTI X{ X#ifdef TTI X register dev = minor(fdev); X#endif TTI X register struct tty *tp = &pts_tty[dev]; X X (*linesw[tp->t_line].l_read)(tp); X} X X#ifndef TTI Xptsclose(dev) X#else TTI Xptsclose(fdev) X#endif TTI X{ X#ifdef TTI X register dev = minor(fdev); X#endif TTI X register struct tty *tp = &pts_tty[dev]; X X (*linesw[tp->t_line].l_close)(tp); X tp->t_state &= ~CARR_ON; X} X X#ifndef TTI Xptsioctl(dev, cmd, arg, mode) X#else TTI Xptsioctl(fdev, cmd, arg, mode) X#endif TTI X{ X#ifdef TTI X register dev = minor(fdev); X#endif TTI X register struct tty *tp = &pts_tty[dev]; X X ttiocom(tp, cmd, arg, mode); X} X Xptsproc(tp, cmd) Xregister struct tty *tp; X{ X register struct ccblock *tbuf; X extern ttrstrt(); X X switch (cmd) { X case T_TIME: X#ifdef DEBUG X printf("T_TIME\n"); X#endif X tp->t_state &= ~TIMEOUT; X goto start; X case T_WFLUSH: X#ifdef DEBUG X printf("T_WFLUSH\n"); X#endif X tp->t_tbuf.c_size -= tp->t_tbuf.c_count; X tp->t_tbuf.c_count = 0; X /* fall through */ X case T_RESUME: X#ifdef DEBUG X printf("T_RESUME\n"); X#endif X tp->t_state &= ~TTSTOP; X /* fall through */ X case T_OUTPUT: X#ifdef DEBUG X printf("T_OUTPUT\n"); X#endif Xstart: X if (tp->t_state & (TTSTOP|TIMEOUT)) X break; X tbuf = &tp->t_tbuf; X if (tbuf->c_ptr == NULL || tbuf->c_count == 0) { X if (tbuf->c_ptr) X tbuf->c_ptr -= tbuf->c_size; X if (!(CPRES & (*linesw[tp->t_line].l_output)(tp))) X break; X } X#ifndef TTI X if (tbuf->c_count && (tp->t_state & MRWAIT)) { X tp->t_state &= ~MRWAIT; X#else TTI X if (tbuf->c_count && (pts_state[tp-pts_tty] & MRWAIT)) { X pts_state[tp-pts_tty] &= ~MRWAIT; X#endif TTI X wakeup((caddr_t)&tp->t_rloc); X } X break; X case T_SUSPEND: X#ifdef DEBUG X printf("T_SUSPEND\n"); X#endif X tp->t_state |= TTSTOP; X break; X case T_BLOCK: X#ifdef DEBUG X printf("T_BLOCK\n"); X#endif X /* X * the check for ICANON appears to be neccessary X * to avoid a hang when overflowing input X */ X if ((tp->t_iflag & ICANON) == 0) X tp->t_state |= TBLOCK; X break; X case T_BREAK: X#ifdef DEBUG X printf("T_BREAK\n"); X#endif X tp->t_state |= TIMEOUT; X timeout(ttrstrt, tp, HZ/4); X break; X#ifdef T_LOG_FLUSH X case T_LOG_FLUSH: X#ifdef DEBUG X printf("T_LOG_FLUSH\n"); X#endif X#endif X case T_RFLUSH: X#ifdef DEBUG X printf("T_RFLUSH\n"); X#endif X if (!(tp->t_state & TBLOCK)) X break; X /* fall through */ X case T_UNBLOCK: X#ifdef DEBUG X printf("T_UNBLOCK\n"); X#endif X tp->t_state &= ~(TTXOFF|TBLOCK); X /* fall through */ X case T_INPUT: X#ifdef DEBUG X printf("T_INPUT\n"); X#endif X#ifndef TTI X if (tp->t_state & MWWAIT) { X tp->t_state &= ~MWWAIT; X#else TTI X if (pts_state[tp-pts_tty] & MWWAIT) { X pts_state[tp-pts_tty] &= ~MWWAIT; X#endif TTI X wakeup((caddr_t)&tp->t_wloc); X } X break; X#ifdef DEBUG X default: X printf("ptsproc: cmd %d\n",cmd); X#endif X } X} X X/* X * master part - not actually like a tty X */ X X#ifndef TTI Xptmopen(dev, flag) X#else TTI Xptmopen(fdev, flag) X#endif TTI X{ X#ifdef TTI X register dev = minor(fdev); X#endif TTI X register struct tty *tp = &pts_tty[dev]; X X#ifdef DEBUG X printf("ptmopen(%d)\n",dev); X#endif X if (dev >= pts_cnt) { X u.u_error = ENXIO; X return; X } X /* X * allow only one controlling process X */ X#ifndef TTI X if (tp->t_state & MOPEN) { X#else TTI X if (pts_state[dev] & MOPEN) { X#endif TTI X u.u_error = EBUSY; X return; X } X if (tp->t_state & WOPEN) X wakeup((caddr_t)&tp->t_canq); X#ifndef TTI X tp->t_state |= CARR_ON|MOPEN; X#else TTI X tp->t_state |= CARR_ON; X pts_state[dev] |= MOPEN; X#endif TTI X} X X#ifndef TTI Xptmread(dev) X#else TTI Xptmread(fdev) X#endif TTI X{ X#ifdef TTI X register dev = minor(fdev); X#endif TTI X register struct tty *tp = &pts_tty[dev]; X register n; X X#ifndef TTI X if ((tp->t_state & ISOPEN) == 0) { X#else TTI X if ((tp->t_state & (ISOPEN|TTIOW)) == 0) { X#ifdef DEBUG X printf("ptmread(%d) EIO\n",dev); X#endif X#endif TTI X u.u_error = EIO; X return; X } X#ifdef DEBUG X printf("ptmread(%d)\n",dev); X#endif X#ifndef TTI X while (u.u_count) { X#else TTI X while (u.u_count>0) { X#endif TTI X ptsproc(tp, T_OUTPUT); X if ((tp->t_state & (TTSTOP|TIMEOUT)) X || tp->t_tbuf.c_ptr == NULL || tp->t_tbuf.c_count == 0) { X if (u.u_fmode & FNDELAY) X break; X#ifndef TTI X tp->t_state |= MRWAIT; X#else TTI X pts_state[dev] |= MRWAIT; X#endif TTI X sleep((caddr_t)&tp->t_rloc, TTIPRI); X continue; X } X n = min(u.u_count, tp->t_tbuf.c_count); X if (n) { X if (copyout(tp->t_tbuf.c_ptr, u.u_base, n)) { X u.u_error = EFAULT; X break; X } X tp->t_tbuf.c_count -= n; X tp->t_tbuf.c_ptr += n; X u.u_base += n; X u.u_count -= n; X } X } X} X X#ifndef TTI Xptmwrite(dev) X#else TTI Xptmwrite(fdev) X#endif TTI X{ X#ifdef TTI X register dev = minor(fdev); X#endif TTI X register struct tty *tp = &pts_tty[dev]; X register n; X X if ((tp->t_state & ISOPEN) == 0) { X u.u_error = EIO; X return; X } X#ifdef DEBUG X printf("ptmwrite(%d)\n",dev); X#endif X#ifndef TTI X while (u.u_count) { X#else TTI X while (u.u_count>0) { X#endif TTI X if ((tp->t_state & TBLOCK) || tp->t_rbuf.c_ptr == NULL) { X if (u.u_fmode & FNDELAY) X break; X#ifndef TTI X tp->t_state |= MWWAIT; X#else TTI X pts_state[dev] |= MWWAIT; X#endif TTI X sleep((caddr_t)&tp->t_wloc, TTOPRI); X continue; X } X n = min(u.u_count, tp->t_rbuf.c_count); X if (n) { X if (copyin(u.u_base,tp->t_rbuf.c_ptr, n)) { X u.u_error = EFAULT; X break; X } X tp->t_rbuf.c_count -= n; X u.u_base += n; X u.u_count -= n; X } X#ifndef TTI X#ifdef vax X#else TTI X#ifdef vax || m68k X#endif TTI X /* X * somebody told me this is necessary on the vax X */ X (*linesw[tp->t_line].l_input)(tp, L_BUF); X#else X (*linesw[tp->t_line].l_input)(tp); X#endif X } X} X X#ifndef TTI Xptmclose(dev) X#else TTI Xptmclose(fdev) X#endif TTI X{ X#ifdef TTI X register dev = minor(fdev); X#endif TTI X register struct tty *tp = &pts_tty[dev]; X X#ifdef DEBUG X printf("ptmclose(%d)\n",dev); X#endif X if (tp->t_state & ISOPEN) { X signal(tp->t_pgrp, SIGHUP); X ttyflush(tp, FREAD|FWRITE); X } X /* X * virtual carrier gone X */ X#ifndef TTI X tp->t_state &= ~(CARR_ON|MOPEN); X#else TTI X tp->t_state &= ~CARR_ON; X pts_state[dev] &= ~MOPEN; X#endif TTI X} X X#ifndef TTI Xptmioctl(dev, cmd, arg, mode) X#else TTI Xptmioctl(fdev, cmd, arg, mode) X#endif TTI X{ X#ifdef TTI X register dev = minor(fdev); X#endif TTI X register struct tty *tp = &pts_tty[dev]; X X /* X * sorry, but we can't fiddle with the tty struct without X * having done LDOPEN X */ X if (tp->t_state & ISOPEN) { X if (cmd == TCSBRK && arg == NULL) { X signal(tp->t_pgrp, SIGINT); X if ((tp->t_iflag & NOFLSH) == 0) X ttyflush(tp, FREAD|FWRITE); X } else { X /* X * we must flush output to avoid hang in ttywait X */ X if (cmd == TCSETAW || cmd == TCSETAF || cmd == TCSBRK X || cmd == TIOCSETP) X ttyflush(FWRITE); X ttiocom(tp, cmd, arg, mode); X } X } X} SHAR_EOF if test 9410 -ne "`wc -c < 'pty.c'`" then echo shar: "error transmitting 'pty.c'" '(should have been 9410 characters)' fi fi exit 0 # End of shell archive