Added reset of TIOCSBRK in dzclose. (MCT)
[unix-history] / usr / src / sys / vax / uba / dz.c
/* dz.c 4.6 %G% */
#include "dz.h"
#if NDZ11 > 0
/*
* DZ-11 Driver
*/
#include "../h/param.h"
#include "../h/systm.h"
#include "../h/tty.h"
#include "../h/dir.h"
#include "../h/user.h"
#include "../h/map.h"
#include "../h/pte.h"
#include "../h/uba.h"
#include "../h/conf.h"
#include "../h/pdma.h"
#include "../h/bk.h"
#include "../h/file.h"
#include "../h/mx.h"
/*
* When running dz's using only SAE (silo alarm) on input
* it is necessary to call dzrint() at clock interrupt time.
* This is unsafe unless spl5()s in tty code are changed to
* spl6()s to block clock interrupts. Note that the dh driver
* currently in use works the same way as the dz, even though
* we could try to more intelligently manage its silo.
* Thus don't take this out if you have no dz's unless you
* change clock.c and dhtimer().
*/
#define spl5 spl6
#define NDZ (NDZ11*8)
#define BITS7 020
#define BITS8 030
#define TWOSB 040
#define PENABLE 0100
#define OPAR 0200
#define MSE 040 /* Master Scan Enable */
#define RIE 0100 /* Receiver Interrupt Enable */
#define SAE 010000 /* Silo Alarm Enable */
#define TIE 040000 /* Transmit Interrupt Enable */
#define DZ_IEN (MSE+RIE+TIE+SAE)
#define PERROR 010000
#define FRERROR 020000
#define OVERRUN 040000
#define SSPEED 7 /* std speed = 300 baud */
#define dzlpr dzrbuf
#define dzmsr dzbrk
#define ON 1
#define OFF 0
int dzstart();
int dzxint();
int ttrstrt();
struct tty dz_tty[NDZ];
int dz_cnt = { NDZ };
int dzact;
struct device {
short dzcsr;
short dzrbuf;
char dztcr;
char dzdtr;
char dztbuf;
char dzbrk;
};
struct pdma dzpdma[] = {
(struct device *)(DZADDR), NULL, NULL, (int)&dz_tty[0], dzxint,
(struct device *)(DZADDR), NULL, NULL, (int)&dz_tty[1], dzxint,
(struct device *)(DZADDR), NULL, NULL, (int)&dz_tty[2], dzxint,
(struct device *)(DZADDR), NULL, NULL, (int)&dz_tty[3], dzxint,
(struct device *)(DZADDR), NULL, NULL, (int)&dz_tty[4], dzxint,
(struct device *)(DZADDR), NULL, NULL, (int)&dz_tty[5], dzxint,
(struct device *)(DZADDR), NULL, NULL, (int)&dz_tty[6], dzxint,
(struct device *)(DZADDR), NULL, NULL, (int)&dz_tty[7], dzxint,
#if NDZ11 >= 2
(struct device *)(DZADDR+010), NULL, NULL, (int)&dz_tty[8], dzxint,
(struct device *)(DZADDR+010), NULL, NULL, (int)&dz_tty[9], dzxint,
(struct device *)(DZADDR+010), NULL, NULL, (int)&dz_tty[10], dzxint,
(struct device *)(DZADDR+010), NULL, NULL, (int)&dz_tty[11], dzxint,
(struct device *)(DZADDR+010), NULL, NULL, (int)&dz_tty[12], dzxint,
(struct device *)(DZADDR+010), NULL, NULL, (int)&dz_tty[13], dzxint,
(struct device *)(DZADDR+010), NULL, NULL, (int)&dz_tty[14], dzxint,
(struct device *)(DZADDR+010), NULL, NULL, (int)&dz_tty[15], dzxint,
#endif
#if NDZ11 >= 3
(struct device *)(DZADDR+020), NULL, NULL, (int)&dz_tty[16], dzxint,
(struct device *)(DZADDR+020), NULL, NULL, (int)&dz_tty[17], dzxint,
(struct device *)(DZADDR+020), NULL, NULL, (int)&dz_tty[18], dzxint,
(struct device *)(DZADDR+020), NULL, NULL, (int)&dz_tty[19], dzxint,
(struct device *)(DZADDR+020), NULL, NULL, (int)&dz_tty[20], dzxint,
(struct device *)(DZADDR+020), NULL, NULL, (int)&dz_tty[21], dzxint,
(struct device *)(DZADDR+020), NULL, NULL, (int)&dz_tty[22], dzxint,
(struct device *)(DZADDR+020), NULL, NULL, (int)&dz_tty[23], dzxint,
#endif
#if NDZ11 >= 4
(struct device *)(DZADDR+030), NULL, NULL, (int)&dz_tty[24], dzxint,
(struct device *)(DZADDR+030), NULL, NULL, (int)&dz_tty[25], dzxint,
(struct device *)(DZADDR+030), NULL, NULL, (int)&dz_tty[26], dzxint,
(struct device *)(DZADDR+030), NULL, NULL, (int)&dz_tty[27], dzxint,
(struct device *)(DZADDR+030), NULL, NULL, (int)&dz_tty[28], dzxint,
(struct device *)(DZADDR+030), NULL, NULL, (int)&dz_tty[29], dzxint,
(struct device *)(DZADDR+030), NULL, NULL, (int)&dz_tty[30], dzxint,
(struct device *)(DZADDR+030), NULL, NULL, (int)&dz_tty[31], dzxint,
#endif
};
char dz_timer;
char dz_speeds[] = {
0, 020 , 021 , 022 , 023 , 024 , 0, 025,
026 , 027 , 030 , 032 , 034 , 036 , 0 , 0,
};
char dz_brk[NDZ11];
/*ARGSUSED*/
dzopen(d, flag)
{
register struct tty *tp;
register dev;
extern dzscan();
dev = minor(d);
if (dev >= dz_cnt) {
u.u_error = ENXIO;
return;
}
if (dz_timer == 0) {
dz_timer++;
timeout(dzscan, (caddr_t)0, 60);
}
tp = &dz_tty[dev];
tp->t_addr = (caddr_t)&dzpdma[dev];
tp->t_oproc = dzstart;
tp->t_iproc = NULL;
tp->t_state |= WOPEN;
if ((tp->t_state & ISOPEN) == 0) {
ttychars(tp);
tp->t_ospeed = tp->t_ispeed = SSPEED;
tp->t_flags = ODDP|EVENP|ECHO;
/*tp->t_state |= HUPCLS;*/
dzparam(dev);
} else if (tp->t_state&XCLUDE && u.u_uid != 0) {
u.u_error = EBUSY;
return;
}
dzmodem(dev, ON);
(void) spl5();
while ((tp->t_state & CARR_ON) == 0) {
tp->t_state |= WOPEN;
sleep((caddr_t)&tp->t_rawq, TTIPRI);
}
(void) spl0();
(*linesw[tp->t_line].l_open)(d, tp);
}
dzclose(d)
{
register struct tty *tp;
register dev;
dev = minor(d);
tp = &dz_tty[dev];
(*linesw[tp->t_line].l_close)(tp);
/*
* Turn the break bit off in case it was left on by a TIOCSBRK
* but not turned off by TIOCCBRK
*/
((struct pdma *)(tp->t_addr))->p_addr->dzbrk =
(dz_brk[minor(dev)>>3] &= ~(1 << (dev&07)));
if (tp->t_state & HUPCLS)
dzmodem(dev, OFF);
ttyclose(tp);
}
dzread(d)
{
register struct tty *tp;
tp = &dz_tty[minor(d)];
(*linesw[tp->t_line].l_read)(tp);
}
dzwrite(d)
{
register struct tty *tp;
tp = &dz_tty[minor(d)];
(*linesw[tp->t_line].l_write)(tp);
}
/*ARGSUSED*/
dzrint(dev)
{
register struct tty *tp;
register int c;
register struct device *dzaddr;
register struct tty *tp0;
int s;
s = spl6(); /* see comment in clock.c */
/* as long as we are here, service them all */
for (dev = 0; dev < NDZ; dev += 8) {
if ((dzact & (1<<(dev>>3))) == 0)
continue;
dzaddr = dzpdma[dev].p_addr;
tp0 = &dz_tty[dev];
while ((c = dzaddr->dzrbuf) < 0) { /* char present */
tp = tp0 + ((c>>8)&07);
if (tp >= &dz_tty[dz_cnt])
continue;
if ((tp->t_state & ISOPEN) == 0) {
wakeup((caddr_t)&tp->t_rawq);
continue;
}
if (c&FRERROR)
/* framing error = break */
if (tp->t_flags & RAW)
c = 0; /* null for getty */
else
#ifdef IIASA
continue;
#else
c = tun.t_intrc;
#endif
if (c&OVERRUN)
printf("o");
if (c&PERROR)
/* parity error */
if (((tp->t_flags & (EVENP|ODDP)) == EVENP)
|| ((tp->t_flags & (EVENP|ODDP)) == ODDP))
continue;
if (tp->t_line == NETLDISC) {
c &= 0177;
BKINPUT(c, tp);
} else
(*linesw[tp->t_line].l_rint)(c, tp);
}
}
splx(s);
}
/*ARGSUSED*/
dzioctl(dev, cmd, addr, flag)
caddr_t addr;
dev_t dev;
{
register struct tty *tp;
tp = &dz_tty[minor(dev)];
cmd = (*linesw[tp->t_line].l_ioctl)(tp, cmd, addr);
if (cmd == 0)
return;
if (ttioctl(tp, cmd, addr, flag)) {
if (cmd==TIOCSETP || cmd==TIOCSETN)
dzparam(minor(dev));
} else switch(cmd) {
case TIOCSBRK:
((struct pdma *)(tp->t_addr))->p_addr->dzbrk =
(dz_brk[minor(dev)>>3] |= 1 << (dev&07));
break;
case TIOCCBRK:
((struct pdma *)(tp->t_addr))->p_addr->dzbrk =
(dz_brk[minor(dev)>>3] &= ~(1 << (dev&07)));
break;
case TIOCSDTR:
dzmodem(minor(dev), ON);
break;
case TIOCCDTR:
dzmodem(minor(dev), OFF);
break;
default:
u.u_error = ENOTTY;
}
}
dzparam(dev)
{
register struct tty *tp;
register struct device *dzaddr;
register short lpr;
tp = &dz_tty[dev];
dzaddr = dzpdma[dev].p_addr;
dzaddr->dzcsr = DZ_IEN;
dzact |= (1<<(dev>>3));
if (tp->t_ispeed == 0) {
dzmodem(dev, OFF); /* hang up line */
return;
}
lpr = (dz_speeds[tp->t_ispeed]<<8) | (dev & 07);
#ifndef IIASA
if (tp->t_flags & RAW)
lpr |= BITS8;
else
lpr |= (BITS7|PENABLE);
if ((tp->t_flags & EVENP) == 0)
lpr |= OPAR;
#else IIASA
if ((tp->t_flags & (EVENP|ODDP)) == (EVENP|ODDP))
lpr |= BITS8;
else if (tp->t_flags & EVENP)
lpr |= (BITS7|PENABLE);
else if (tp->t_flags & ODDP)
lpr |= (BITS7|OPAR|PENABLE);
else
lpr |= BITS7;
#endif IIASA
if (tp->t_ispeed == 3)
lpr |= TWOSB; /* 110 baud: 2 stop bits */
dzaddr->dzlpr = lpr;
}
dzxint(tp)
register struct tty *tp;
{
register struct pdma *dp;
register s;
s = spl6(); /* block the clock */
dp = &dzpdma[tp-dz_tty];
tp->t_state &= ~BUSY;
if (tp->t_state & FLUSH)
tp->t_state &= ~FLUSH;
else
ndflush(&tp->t_outq, dp->p_mem-tp->t_outq.c_cf);
if (tp->t_line)
(*linesw[tp->t_line].l_start)(tp);
else
dzstart(tp);
if (tp->t_outq.c_cc == 0 || (tp->t_state&BUSY)==0)
dp->p_addr->dztcr &= ~(1 << ((tp-dz_tty) % 8));
splx(s);
}
dzstart(tp)
register struct tty *tp;
{
register struct pdma *dp;
register struct device *dzaddr;
register cc;
int sps;
dp = &dzpdma[tp-dz_tty];
dzaddr = dp->p_addr;
sps = spl5();
if (tp->t_state & (TIMEOUT|BUSY|TTSTOP))
goto out;
if (tp->t_state&ASLEEP && tp->t_outq.c_cc <= TTLOWAT(tp)) {
tp->t_state &= ~ASLEEP;
if (tp->t_chan)
mcstart(tp->t_chan, (caddr_t)&tp->t_outq);
else
wakeup((caddr_t)&tp->t_outq);
}
if (tp->t_outq.c_cc == 0)
goto out;
if (tp->t_flags&RAW)
cc = ndqb(&tp->t_outq, 0);
else {
cc = ndqb(&tp->t_outq, 0200);
if (cc == 0) {
cc = getc(&tp->t_outq);
timeout(ttrstrt, (caddr_t)tp, (cc&0177) + 6);
tp->t_state |= TIMEOUT;
goto out;
}
}
tp->t_state |= BUSY;
dp->p_end = dp->p_mem = tp->t_outq.c_cf;
dp->p_end += cc;
dzaddr->dztcr |= 1 << ((tp-dz_tty) % 8);
out:
splx(sps);
}
/*
* Stop output on a line.
* Assume call is made at spl6.
*/
/*ARGSUSED*/
dzstop(tp, flag)
register struct tty *tp;
{
register struct pdma *dp;
register int s;
dp = &dzpdma[tp-dz_tty];
s = spl6();
if (tp->t_state & BUSY) {
dp->p_end = dp->p_mem;
if ((tp->t_state&TTSTOP)==0) {
tp->t_state |= FLUSH;
}
}
splx(s);
}
dzmodem(dev, flag)
register int dev;
{
register struct device *dzaddr;
register char bit;
dzaddr = dzpdma[dev].p_addr;
bit = 1<<(dev&07);
if (flag == OFF)
dzaddr->dzdtr &= ~bit;
else
dzaddr->dzdtr |= bit;
}
dzscan()
{
register i;
register struct device *dzaddr;
register bit;
register struct tty *tp;
for (i = 0; i < dz_cnt ; i++) {
dzaddr = dzpdma[i].p_addr;
tp = &dz_tty[i];
bit = 1<<(i&07);
if (dzaddr->dzmsr & bit) {
/* carrier present */
if ((tp->t_state & CARR_ON) == 0) {
wakeup((caddr_t)&tp->t_rawq);
tp->t_state |= CARR_ON;
}
} else {
if ((tp->t_state&CARR_ON) && (tp->t_local&LNOHANG) == 0) {
/* carrier lost */
if (tp->t_state&ISOPEN) {
gsignal(tp->t_pgrp, SIGHUP);
gsignal(tp->t_pgrp, SIGCONT);
dzaddr->dzdtr &= ~bit;
flushtty(tp, FREAD|FWRITE);
}
tp->t_state &= ~CARR_ON;
}
}
}
timeout(dzscan, (caddr_t)0, 2*HZ);
}
dztimer()
{
dzrint(0);
}
/*
* Reset state of driver if UBA reset was necessary.
* Reset parameters and restart transmission on open lines.
*/
dzreset()
{
int d;
register struct tty *tp;
printf(" dz");
for (d = 0; d < NDZ; d++) {
tp = &dz_tty[d];
if (tp->t_state & (ISOPEN|WOPEN)) {
dzparam(d);
dzmodem(d, ON);
tp->t_state &= ~BUSY;
dzstart(tp);
}
}
dztimer();
}
#endif