Ausam/sys/dmr/dz.c
/*
* DZ-11 driver
* ------------
*
* Written to handle single dz - `carrier'|`ring' support non-existent
*
* Piers Lauder
* SYDNEY UNIVERSITY
* July 1977
*
* Re-written to handle multiple dz's and `carrier'|`ring'.
*
* Ian Johnstone
* UNSW
* December 1977
* January 1978
*
* General tidy up, new comments etc. Removal of ifdefs
* for CARRIER and RING. If you don't want them, tough.
*
* Chris Maltby
* Basser October 1979
*/
/* ( no messages )
#define MESSAGES
/*
* Define this if you want parity and framing errors
* to be logged (via printf). It can be very wordy.
*/
#define INTR_ON_BREAK
/*
* Define this to translate framing errors (breaks)
* to CINTR for terminals which lack a DEL key.
* Can be nasty if you get lots of line errors.
*/
/* (not DEBUG)
#define DEBUG
/*
* Define to debug info for dialup lines.
* costs approximately 128 bytes
*/
#include "../defines.h"
#include "../param.h"
#ifdef DEBUG
#ifdef AUSAML
#include "../lnode.h"
#endif AUSAML
#include "../systm.h"
#endif DEBUG
#include "../conf.h"
#include "../user.h"
#include "../tty.h"
#include "../proc.h"
#define NDZ 2 /* number of DZ-11s */
#define NLINES 8*NDZ /* total number of lines */
#define TSCANRATE 2 /* dzscan called every 2 tics */
/* Must be >= 2 always */
#define RESPONDTIME (25*HZ) /* Carrier must be raised inside this */
#define CARRIERTIME (1*HZ) /* Carrier must drop for this before hangup */
#define FLUSHTIME 5 /* time required to allow hardware buffered
* characters to flush before setting speed */
#define SSPEED 12 /* standard speed 4800 bd */
struct dz /* one for each dz-11 */
{
int *dzaddr; /* dz device address */
char sopen; /* bit set for single open lines */
char carrier; /* bits set for carrier controlled lines */
char ring; /* bits set for lines with dial in modems */
char active; /* bits set for active dialup lines */
char openl; /* bits set for open lines */
unsigned pyerrors; /* count of of parity errors on input */
unsigned overrors; /* count of of overrun errors on input */
}
dz[NDZ]
{
/* dzaddr sopen carr ring */
{ 0160040, 0002, 0077, 0074 },
{ 0160050, 0000, 0000, 0000 }
};
int dzscanning; /* set when scanning for input and modem change */
/*
* DZ11 register layout
*/
struct dzr_read
{
int dzcsr; /* r/w */
int dzrbuf; /* no bit, byte, or tst ops */
char dztcr; /* r/w */
char dzdtr; /* r/w */
char dzring;
char dzcarr;
};
struct dzr_write
{
int dzcsr; /* r/w */
int dzlpr; /* no bit or byte ops */
char dztcr; /* r/w */
char dzdtr; /* r/w */
char dztbuf; /* no bit ops */
char dzbrk; /* no bit ops */
};
/*
* register control bits
*/
#define TRDY 0100000 /* dzcsr */
#define TIE 040000
#define SA 020000
#define SAE 010000
#define TLINE 03400
#define RDONE 0200
#define RIE 0100
#define MSE 040
#define CLR 020
#define RCVR_ON 010000 /* dzlpr */
#define S9600 07000
#define S300 02400
#define S134_5 01400
#define S110 01000
#define ODD_PAR 0300
#define EVN_PAR 0100
#define TWOSBIT 040
#define C8BIT 030
#define C7BIT 020
#define C6BIT 010
/*
#define IBM2741 RCVR_ON|S134_5|ODD_PAR|C6BIT /* if you must */
#define RERROR 070000 /* dzrbuf */
#define OVR_RUN 040000
#define FRAME 020000
#define PARITY 010000
#define LINE_NO 03400
/*
* table to map UNIX standard speeds to DZ11 speeds
* illegal speeds are ignored.
*/
char dzspeedmap[16]
{
0 /* 0 - zero */
, 020 /* 1 - 50 */
, 021 /* 2 - 75 */
, 022 /* 3 - 110 */
, 023 /* 4 - 134.5 */
, 024 /* 5 - 150 */
,0200 /* 6 - 200 -- ## ILLEGAL ## */
, 025 /* 7 - 300 */
, 026 /* 8 - 600 */
, 027 /* 9 - 1200 */
, 030 /* 10 - 1800 */
, 032 /* 11 - 2400 */
, 034 /* 12 - 4800 */
, 036 /* 13 - 9600 */
, 031 /* 14 - ext A - maps to 2000 */
, 037 /* 15 - ext B - maps to 19200 */
};
struct tty dz11[NLINES];
char dzdelays[NLINES]; /* Count of clock ticks for per-line
* delays. Count of <= 0 means no delay.
* Reduces requirement of timeouts.
*/
int dzringt[NLINES]; /* Delay counts for modem control */
/*
* open a DZ11 line
*/
dzopen(dev, flag)
{
register struct tty *tp;
register struct dz *dzp;
register int t_bit;
extern dzstart(), dzscan();
if(dev.d_minor >= NLINES)
{
u.u_error = ENXIO;
return;
}
dzp = &dz[dev.d_minor>>3];
t_bit = (1<<(dev.d_minor&07));
if((dzp->sopen&t_bit) && (dzp->openl&t_bit))
{
u.u_error = EOPENFAIL;
return;
}
tp = &dz11[dev.d_minor];
if(u.u_procp->p_ttyp == 0)
u.u_procp->p_ttyp = tp;
if((tp->t_state&ISOPEN) == 0)
{
tp->t_dev = dev;
tp->t_addr = &dzstart;
tp->t_speeds = SSPEED|(SSPEED<<8);
tp->t_flags = ODDP|EVENP|XTABS|RAW;
tp->t_erase = CERASE;
tp->t_kill = CKILL;
if(dzp->openl == 0)
dzp->dzaddr->dzcsr =| (TIE|RIE|SAE|MSE); /* reciever interrupt every 16 chars */
dzp->openl =| t_bit;
spl5();
if(dzscanning == 0)
dzscan(); /* start scanning */
if(!(dzp->ring&t_bit) && !(dzp->carrier&t_bit))
dzp->dzaddr->dzdtr =| t_bit; /* turn on DTR for non-dialup lines */
else
{
# ifdef DEBUG
printf("%d wo%d\n", time.loint, dev.d_minor);
# endif DEBUG
while(!(dzp->dzaddr->dzcarr&t_bit))
{
tp->t_state =| WOPEN;
sleep(&tp->t_rawq, TTIPRI);
}
# ifdef DEBUG
printf("%d op%d\n", time.loint, dev.d_minor);
# endif DEBUG
}
spl0();
tp->t_state = (ISOPEN|CARR_ON|SSTART);
dzparam(tp, 1);
}
}
/*
* scan open lines for:
* 1. modem status changes
* 2. process timeouts as dictated by dzdelays
* 3. input by calling dzrint
*/
dzscan() /* at spl5 */
{
register struct dz *dzp;
struct tty *tp;
int *p;
extern dzstart(), dzrint(), dzscan();
# define openring (dzp->openl & dzp->ring)
# define opencarrier (dzp->openl & dzp->carrier)
/*
* scan open dialup/carrier lines.
*/
tp = &dz11[0];
p = &dzringt[0];
for(dzp = dz; dzp < &dz[NDZ]; dzp++)
{
register int *dzaddr;
char scanl, scanc;
dzaddr = dzp->dzaddr;
if((scanl = openring) | (scanc = opencarrier))
{
register int t_bit;
for(t_bit = 1; t_bit&0377; t_bit =<< 1, tp++, p++)
{
if(scanl&t_bit)
{
/* this is an open `dialup' line */
if(dzp->active&t_bit)
{
if(!(dzaddr->dzcarr&t_bit))
{
if(*p == 0)
*p = CARRIERTIME;
else if((*p =- TSCANRATE) <= 0)
{
*p = 0; /* disable */
# ifdef DEBUG
printf("%d hu%d\n", time.loint, tp->t_dev.d_minor);
# endif DEBUG
dzaddr->dzdtr =& ~t_bit; /* hang up the phone */
signal(tp, SIGHUP);
flushtty(tp);
dzaddr->dztcr =& ~t_bit; /* disable transmit */
dzp->active =& ~t_bit;
}
}
else
{
if(tp->t_state&WOPEN)
wakeup(&tp->t_rawq);
*p = 0;
if(!(tp->t_state&TIMEOUT) && (tp->t_outq.c_cc))
dzaddr->dztcr =| t_bit;
}
}
else
{
if(!(dzaddr->dzdtr&t_bit) && (dzaddr->dzring&t_bit))
{
dzaddr->dzdtr =| t_bit; /* answer the phone */
*p = RESPONDTIME;
dzp->active =| t_bit;
# ifdef DEBUG
printf("%d ap%d\n", time.loint, tp->t_dev.d_minor);
# endif DEBUG
}
}
}
else if((scanc&t_bit) && (dzaddr->dzcarr&t_bit))
{ /* carrier only line */
if(tp->t_state&WOPEN)
{
dzaddr->dzdtr =| t_bit;
wakeup(&tp->t_rawq);
}
else if((!(tp->t_state&TIMEOUT)) && (tp->t_outq.c_cc))
dzaddr->dztcr =| t_bit;
}
}
}
else
{
tp =+ 8; p =+ 8; /* in the case where no dialup/carrier lines on current dz */
}
}
/*
* process timeouts for each line
*/
{
register i;
for(i = 0; i < NLINES; i++)
if((dzdelays[i] > 0) && (--dzdelays[i] <= 0))
{
dz11[i].t_state =& ~TIMEOUT;
dzstart(&dz11[i]);
}
}
/*
* scan each dz for input
*/
dzrint(0);
/*
* restart scanning if necessary
*/
dzp = dz;
do
{
if(dzp->openl)
{
dzscanning = timeout(&dzscan, 0, TSCANRATE);
return;
}
dzp++;
} while(dzp < &dz[NDZ]);
dzscanning = 0;
}
/*
* close a DZ11 line
*/
dzclose(dev)
{
register struct tty *tp;
register t_bit;
register struct dz *dzp;
tp = &dz11[dev.d_minor];
wflushtty(tp);
tp->t_state = SSTART;
dzp = &dz[dev.d_minor>>3];
t_bit = 1<<(dev.d_minor&07);
if(dzp->ring&t_bit)
{
if(tp->t_flags&HUPCL)
dzp->dzaddr->dzdtr =& ~t_bit; /* hang up the phone */
}
else
{
dzp->dzaddr->dzdtr =& ~t_bit; /* turn off dtr for non-dialup lines */
}
if((dzp->openl =& ~t_bit) == 0)
dzp->dzaddr->dzcsr = 0; /* disable receive on final close */
}
/*
* read from a DZ11 line
*/
dzread(dev)
{
ttread(&dz11[dev.d_minor]);
}
/*
* write on a DZ11 line
*/
dzwrite(dev)
{
ttwrite(&dz11[dev.d_minor]);
}
/*
* stty/gtty for DZ11
*/
dzsgtty(dev, av)
int *av;
{
register struct tty *tp;
if((av == 0) && (dzspeedmap[u.u_arg[0]&017] < 0))
{
u.u_error = ENXIO; /* illegal speed */
return;
}
tp = &dz11[dev.d_minor];
if(ttystty(tp, av))
return;
dzparam(tp, 1);
}
/*
* set parameters from open or stty into DZ hardware registers
*/
dzparam(tp, dflag)
register struct tty *tp;
{
register lpr, x;
extern wakeup();
lpr = dzspeedmap[tp->t_speeds&017]<<8;
#ifdef IBM2741
if(lpr == (RCVR_ON|S134_5))
lpr = IBM2741;
else
{
#endif IBM2741
if(lpr == (RCVR_ON|S110))
lpr =| TWOSBIT;
if((x = tp->t_flags)&EVENP)
if((x&ODDP) == 0)
lpr =| (EVN_PAR|C7BIT);
else
lpr =| C8BIT;
else if(x&ODDP)
lpr =| (ODD_PAR|C7BIT);
else
lpr =| C8BIT;
#ifdef IBM2741
}
#endif IBM2741
if(dflag)
{
/* delay only if it is permissible */
#ifndef DELAY
timeout(&wakeup, tp, FLUSHTIME); /* wakeup in 5 tics */
sleep(tp, TTOPRI); /* delay while controller flushes */
#else
delay(FLUSHTIME); /* hang 5 */
#endif DELAY
}
dz[tp->t_dev.d_minor>>3].dzaddr->dzlpr = lpr|(tp->t_dev.d_minor&07);
}
/*
* start (restart) transmission on a DZ11 line
*/
dzstart(tp)
register struct tty *tp;
{
register t_bit;
register struct dz *dzp;
t_bit = 1<<(tp->t_dev.d_minor&07);
dzp = &dz[tp->t_dev.d_minor>>3];
if((!(dzp->carrier&t_bit)) || (dzp->dzaddr->dzcarr&t_bit))
dzp->dzaddr->dztcr =| t_bit;
}
/*
* DZ11 transmitter interrupt.
*
* Scan every line on each dz.
* Commencing with the device that caused
* dzxint to be called.
*/
dzxint(dev)
{
register struct tty *tp;
register c;
register struct dzr_read *dzaddr;
struct dz *dzp;
struct tty *dzbase;
int t_bit, lino, i, n;
n = dev.d_minor;
for(i = 0; i < NDZ; i++)
{
dzaddr = (dzp = &dz[n])->dzaddr;
dzbase = &dz11[n*8];
while((c = dzaddr->dzcsr) < 0) /* xmit line ready */
{
t_bit = 1<<(lino = (c>>8)&07);
tp = &dzbase[lino];
if((!(dzp->carrier&t_bit) || (dzaddr->dzcarr&t_bit)) && (c = getc(&tp->t_outq)) >= 0)
if(c <= 0177 || tp->t_flags == RAW)
dzaddr->dztbuf = c;
else
{
dzaddr->dztcr =& ~t_bit;
tp->t_state =| TIMEOUT;
dzdelays[tp-dz11] = ((c&0177)+(TSCANRATE-1))/TSCANRATE+1; /* set up timeout */
continue;
}
else
dzaddr->dztcr =& ~t_bit;
#ifdef TTY_HISPEED
if(tp->t_outq.c_cc <= ((tp->t_speeds&017) > B1200?TTHSLOWAT:TTLOWAT) && (tp->t_state&ASLEEP))
#else
if(tp->t_outq.c_cc <= TTLOWAT && (tp->t_state&ASLEEP))
#endif TTY_HISPEED
{
tp->t_state =& ~ASLEEP;
wakeup(&tp->t_outq);
}
}
if(++n >= NDZ)
n = 0;
}
}
/*
* DZ11 receiver interrupt
*
* Scan each dz commencing with the
* particular device that caused this call.
* Storing each charater as it comes.
*/
dzrint(dev)
{
register struct tty *tp;
register c;
register struct dzr_read *dzaddr;
struct dz *dzp;
struct tty *dzbase;
int i, n, lino, t_bit;
n = dev.d_minor;
for(i = 0; i < NDZ; i++)
{
dzp = &dz[n];
if(dzp->openl)
{
dzbase = &dz11[n*8];
while((c = dzp->dzaddr->dzrbuf) < 0) /* char present in silo */
{
tp = &dzbase[lino = ((c>>8)&07)];
t_bit = 1<<lino;
if(c&RERROR)
{
if(c&OVR_RUN)
{
dzp->overrors++;
# ifdef MESSAGES
printf("over run on dz %d/%d\n", n, lino);
# endif MESSAGES
}
if(c&FRAME) /* break */
if(tp->t_flags&RAW)
c = 0; /* null ( for getty ) */
else
# ifdef INTR_ON_BREAK
c = CINTR; /* del for NCRs. */
# else
continue; /* ignore framing errors if not raw */
# endif INTR_ON_BREAK
else if(c&PARITY)
{
dzp->pyerrors++;
# ifdef MESSAGES
printf("parity on dz %d/%d\n", n, lino);
# endif MESSAGES
continue; /* throw away bad chars */
}
}
if((!(dzp->carrier&t_bit)) || (dzp->dzaddr->dzcarr&t_bit))
ttyinput(c, tp);
}
}
if(++n >= NDZ)
n = 0;
}
}
#ifdef POWER_FAIL
dzpowf()
{
register line;
register struct dz *dzp;
register struct tty *tp;
int dzn, t_bit;
tp = &dz11[0];
for(dzn = 0; dzn < NDZ; dzn++)
{
dzp = &dz[dzn];
if(dzp->openl)
{
(dzp->dzaddr)->dzcsr =| (TIE|RIE|SAE|MSE); /* reciever interrupt every 16 chars */
for(line = 0; line < 8; line++, tp++)
if(tp->t_state&ISOPEN)
{
t_bit = 1<<line;
dzparam(tp, 0); /* set speeds */
(dzp->dzaddr)->dztcr =| t_bit; /* enable transmit */
if(!(dzp->ring&t_bit))
dzp->dzaddr->dzdtr =| t_bit; /* turn on DTR for non-dialup li n e s */
}
}
else
tp =+ 8;
}
}
#endif POWER_FAIL