SysIII/usr/src/uts/pdp11/io/dh.c

Compare this file to the similar file:
Show the results in this format:

/*
 *	DH11 & DM11-BB driver for multiple units
 */

#include "sys/param.h"
#include "sys/dir.h"
#include "sys/user.h"
#include "sys/file.h"
#include "sys/tty.h"
#include "sys/conf.h"
#include "sys/sysinfo.h"

struct device *dh_addr[];
int	dh_cnt;
struct tty dh_tty[];
struct inter dm_inter[];
short	dhsar[8];
static char dh_xon = CSTART;
static char dh_xoff = CSTOP;

#define	BITS6	01
#define	BITS7	02
#define	TWOSB	04
#define	PENABLE	020
#define	OPAR	040

#define	IENAB	030100
#define	XINT	0100000
#define	CLRNEM	0400

struct device {
	short dhcsr, dhnxch, dhlpr, dhcar;
	short dhbcr, dhbar, dhbrk, dhsilo;
};

struct devdm *dm_addr[];

#define	DONE	0200
#define	SCENABL	040
#define	BSY	020
#define	TURNON	07	/* RTS, DTR, line enable */
#define	TURNOFF	1	/* line enable only */
#define	CARRIER	0100

struct devdm {
	short	dmcsr, dmlstat;
};

dhopen(dev, flag)
{
	register struct tty *tp;
	extern dhproc();

	if (dev >= dh_cnt) {
		u.u_error = ENXIO;
		return;
	}
	tp = &dh_tty[dev];
	if ((tp->t_state&(ISOPEN|WOPEN)) == 0) {
		ttinit(tp);
		tp->t_proc = dhproc;
		dhparam(dev);
	}
	spl5();
	if (tp->t_cflag&CLOCAL || dmctl(dev, TURNON)&CARRIER)
		tp->t_state |= CARR_ON;
	if (!(flag&FNDELAY))
	while ((tp->t_state&CARR_ON)==0) {
		tp->t_state |= WOPEN;
		sleep(&tp->t_canq, TTIPRI);
	}
	(*linesw[tp->t_line].l_open)(tp);
	spl0();
}

dhclose(dev)
{
	register struct tty *tp;

	tp = &dh_tty[dev];
	(*linesw[tp->t_line].l_close)(tp);
	if (tp->t_cflag&HUPCL) {
		spl5();
		dmctl(dev, TURNOFF);
		spl0();
	}
}

dhread(dev)
{
	register struct tty *tp;

	tp = &dh_tty[dev];
	(*linesw[tp->t_line].l_read)(tp);
}

dhwrite(dev)
{
	register struct tty *tp;

	tp = &dh_tty[dev];
	(*linesw[tp->t_line].l_write)(tp);
}

dhioctl(dev, cmd, arg, mode)
register dev;
{
	switch(cmd) {
	default:
		if (ttiocom(&dh_tty[dev], cmd, arg, mode))
			dhparam(dev);
	}
}

dhparam(dev)
{
	register struct tty *tp;
	register flags, lpr;
	register struct device *rp;

	tp = &dh_tty[dev];
	rp = dh_addr[dev>>4];
	flags = tp->t_cflag;
	lpr = (flags&CBAUD)<<10;
	if (flags&CREAD)
		lpr |= (flags&CBAUD)<<6;
	if (flags&CS6)
		lpr |= BITS6;
	if (flags&CS7)
		lpr |= BITS7;
	if (flags&PARENB) {
		lpr |= PENABLE;
		if (flags&PARODD)
			lpr |= OPAR;
	}
	if (flags&CSTOPB)
		lpr |= TWOSB;
	spl5();
	rp->dhcsr &= ~017;
	rp->dhcsr |= (dev&017) | IENAB;
	if ((flags&CBAUD) == 0) {
		/* Hang up line */
		if (tp->t_state&CARR_ON) {
			rp->dhbcr = -1;
			dmctl(dev, TURNOFF);
		}
		spl0();
		return;
	}
	rp->dhlpr = lpr;
	spl0();
}

dhrint(dev)
{
	register struct tty *tp;
	register c;
	register struct device *rp;

	sysinfo.rcvint++;
	rp = dh_addr[dev];
	while ((c = rp->dhnxch) < 0) {	/* char. present */
		tp = &dh_tty[((c>>8)&017)|(dev<<4)];
		if (tp >= &dh_tty[dh_cnt])
			continue;
		if (!(tp->t_state&(ISOPEN|WOPEN)))
			continue;
		(*linesw[tp->t_line].l_input)(tp, c, 0);
	}
}

/*
 * DH11 transmitter interrupt.
 * Restart each line which used to be active but has
 * terminated transmission since the last interrupt.
 */
dhxint(dev)
{
	register struct tty *tp;
	register ttybit, bar;
	struct device *rp;
	short *sbar;

	sysinfo.xmtint++;
	rp = dh_addr[dev];
	rp->dhcsr &= ~XINT;
	rp->dhcsr |= CLRNEM;
	sbar = &dhsar[dev];
	bar = *sbar & ~rp->dhbar;
	dev <<= 4;
	ttybit = 1;
	for (; bar; dev++, ttybit <<= 1) if (bar&ttybit) {
		tp = &dh_tty[dev];
		bar &= ~ttybit;
		lobyte(rp->dhcsr) = (dev&017) | IENAB;
		if (tp->t_state&BUSY) {
			register n;

			tp->t_state &= ~BUSY;
			n = rp->dhcar - &tp->t_buf->c_data[tp->t_buf->c_first];
			tp->t_buf->c_first += n;
		}
		if (tp->t_state&TTXON) {
			tp->t_state &= ~TTXON;
			rp->dhcar = &dh_xon;
			rp->dhbcr = -1;
			rp->dhbar |= ttybit;
			continue;
		}
		if (tp->t_state&TTXOFF) {
			tp->t_state &= ~TTXOFF;
			rp->dhcar = &dh_xoff;
			rp->dhbcr = -1;
			rp->dhbar |= ttybit;
			continue;
		}
		*sbar &= ~ttybit;
		dhproc(tp, T_OUTPUT);
	}
}

dhproc(tp, cmd)
register struct tty *tp;
{
	register struct device *rp;
	register n;
	char	*cp;
	int	dev, ttybit;
	extern ttrstrt();

	dev = tp - dh_tty;
	rp = dh_addr[dev>>4];
	ttybit = 1 << (dev&017);
	switch(cmd) {

	case T_TIME:
		tp->t_state &= ~TIMEOUT;
		rp->dhbrk &= ~ttybit;
		goto start;

	case T_WFLUSH:
	case T_RESUME:
		tp->t_state &= ~TTSTOP;
		goto start;

	case T_OUTPUT:
	start:
		if (tp->t_state&(TIMEOUT|TTSTOP|BUSY))
			break;
		if (tp->t_buf && tp->t_buf->c_first >= tp->t_buf->c_last) {
			putcf(tp->t_buf);
			tp->t_buf = NULL;
		}
		if (tp->t_buf == NULL) {
			if ((tp->t_buf = getcb(&tp->t_outq)) == NULL) {
				if (tp->t_state&TTIOW) {
					tp->t_state &= ~TTIOW;
					wakeup((caddr_t)&tp->t_oflag);
				}
				goto dd;
			}
		}
		n = tp->t_buf->c_last - tp->t_buf->c_first;
		cp = &tp->t_buf->c_data[tp->t_buf->c_first];
		if (tp->t_oflag&OPOST) {
			register char *p;
	
			p = cp;
			do {
				if (((*p++)&0377) == 0200) {
					p--;
					break;
				}
			} while(--n);
			n = p - cp;
		}
		if (n == 0) {
			if ((tp->t_buf->c_first+1) == tp->t_buf->c_last) {
				n = getc(&tp->t_outq);
				*cp = n;
			} else {
				tp->t_buf->c_first++;
				cp++;
				n = *cp & 0377;
			}
			if (n > 0200) {
				tp->t_buf->c_first++;
				timeout(ttrstrt, tp, (n&0177)+6);
				tp->t_state |= TIMEOUT;
				goto dd;
			}
			n = 1;
		}
		lobyte(rp->dhcsr) = (dev&017) | IENAB;
		rp->dhcar = cp;
		rp->dhbcr = -n;
		rp->dhbar |= ttybit;
		dhsar[dev>>4] |= ttybit;
		tp->t_state |= BUSY;
	dd:
		if (tp->t_state&OASLP &&
		    tp->t_outq.c_cc <= ttlowat[tp->t_cflag&CBAUD]) {
			tp->t_state &= ~OASLP;
			wakeup((caddr_t)&tp->t_outq);
		}
		break;

	case T_SUSPEND:
		tp->t_state |= TTSTOP;
		if (tp->t_state&BUSY) {
			lobyte(rp->dhcsr) = (dev&017) | IENAB;
			rp->dhbcr = -1;
		}
		break;

	case T_BLOCK:
		tp->t_state |= TBLOCK;
		tp->t_state &= ~TTXON;
		lobyte(rp->dhcsr) = (dev&017) | IENAB;
		if (tp->t_state&BUSY) {
			tp->t_state |= TTXOFF;
			rp->dhbcr = -1;
		} else {
			rp->dhcar = &dh_xoff;
			rp->dhbcr = -1;
			rp->dhbar |= ttybit;
			dhsar[dev>>4] |= ttybit;
		}
		break;

	case T_RFLUSH:
		if (!(tp->t_state&TBLOCK))
			break;

	case T_UNBLOCK:
		tp->t_state &= ~(TTXOFF|TBLOCK);
		lobyte(rp->dhcsr) = (dev&017) | IENAB;
		if (tp->t_state&BUSY) {
			tp->t_state |= TTXON;
			rp->dhbcr = -1;
		} else {
			rp->dhcar = &dh_xon;
			rp->dhbcr = -1;
			rp->dhbar |= ttybit;
			dhsar[dev>>4] |= ttybit;
		}
		break;

	case T_BREAK:
		rp->dhbrk |= ttybit;
		tp->t_state |= TIMEOUT;
		timeout(ttrstrt, tp, HZ/4);
		break;
	}
}

/*
 * Dump control bits into the DM registers.
 */
dmctl(dev, bits)
register dev;
{
	register struct devdm *dmaddr;
	register svcsr;

	sysinfo.mdmint++;
	dmaddr = dm_addr[dev>>4];
	dmaddr->dmcsr &= ~SCENABL;
	while((svcsr=dmaddr->dmcsr)&BSY);
	dmaddr->dmcsr = dev&017;
	dmaddr->dmlstat = bits;
	dev = dmaddr->dmlstat;
	dmaddr->dmcsr = svcsr|IENAB|SCENABL;
	return(dev);
}

/*
 * DM11 interrupt.
 * Mainly, deal with carrier transitions.
 */
dmintr(dev)
{
	register struct tty *tp;
	register struct devdm *dmaddr;
	register unit;

	dmaddr = dm_addr[dev];
	unit = (dmaddr->dmcsr&017)|(dev<<4);
	if (unit>=dh_cnt) {
		dmaddr->dmlstat = 0;
		dmaddr->dmcsr &= ~DONE;
		return;
	}
	tp = &dh_tty[unit];
	dm_inter[unit].cnt++;
	if (tp->t_cflag&CLOCAL) {
		dmaddr->dmlstat = 0;
		dmaddr->dmcsr &= ~DONE;
		return;
	}
	if (dmaddr->dmlstat&CARRIER) {
		if ((tp->t_state&CARR_ON)==0) {
			wakeup(&tp->t_canq);
			tp->t_state |= CARR_ON;
		}
	} else {
		if (tp->t_state&CARR_ON) {
			if (tp->t_state&ISOPEN) {
				signal(tp->t_pgrp, SIGHUP);
				dmaddr->dmlstat = 0;
				ttyflush(tp, FREAD|FWRITE);
			}
			tp->t_state &= ~CARR_ON;
		}
	}
	dmaddr->dmcsr &= ~DONE;
}

dhclr()
{
	register dev;
	register struct tty *tp;

	for (dev = 0; dev < dh_cnt; dev++) {
		tp = &dh_tty[dev];
		if ((tp->t_state&(ISOPEN|WOPEN)) == 0)
			continue;
		dhparam(dev);
		dmctl(dev, TURNON);
		tp->t_state &= ~BUSY;
		dhproc(tp, T_OUTPUT);
	}
}