BBN-V6/dmr/dz.c
#
/*
module name:
dz.c
function:
Device driver for the DEC dz11 8 line asynchronous multiplexor
globals containied:
dz11 array of tty structures for the dz11 lines
dzaddrs array of addresses of the various dz11 controllers
dzmodem array specifying which dz ports have modem control
dzcycling whether or not modem control is cycling
routines contained:
dzopen open system call routine
dzclose close system call routine
dzread read system call routine
dzwrite write system call routine
dzrint receive interrupt routine
dzxint transmit interrupt routine
dzstart I/O startup routine
dzsgtty sgtty system call routine
dzparam hardare parameter setting routine
dzstatus modem control cycling routine
routines referenced:
ttread, ttwrite, ttyinput, ttystty, ttrstrt
sleep, wakeup
timeout
issig, psig
modules referenced:
user.h needed because of the error code definitions
param.h contains constants required by user.h
conf.h contains the device structure definition
tty.h contains definition of tty structure
options.h to get system compile time parameters
compile time parameters:
UCLATTY define this if you are using the ucla tty.c
leave this undefined if you are using the standard one
history:
Designed and coded by Mark Kampe, 9/27/77.
Modified by BBN(dan) 3/2/79: Moved awake call so it
is now done whenever output count is less than TTLOWAT.
Modified by BBN(dan) 4/9/79: made use new await interface.
*/
#include "../h/param.h"
#include "../h/conf.h"
#include "../h/inode.h"
#include "../h/user.h"
#include "../h/tty.h"
#define true 0177777
#define false 0000000
#define then /* */
#define NDZ11 8
#define DZRATE 300 /* sample modem status every 5 seconds */
struct tty dz11[ NDZ11 ];
/* specification of which lines have modem control enabled */
char dzmodem[ NDZ11 ] /* Setting the i'th entry to a 1 */
{ 0, 0, 0, 0, 0, 0, 0, 0, }; /* enables modem control on that */
/* line. Although this array is */
/* statically initialized, it can */
/* be changed dynamically. */
int dzcycling; /* whether or not the dz has a modem test
pending on any modem controlled lines */
extern ttrstrt();
int dzstart();
struct dzregs /* the readable DZ11 registers */
{ int dzcsr; /* control status register */
int dzrcv; /* receive buffer register */
int dztcr; /* transmit control register */
int dzmsr; /* modem status register */
};
struct /* the writeable DZ11 registers */
{ int dzcsr; /* control status register */
int dzlpr; /* line parameter register */
int dztcr; /* transmit control register */
int dztdr; /* transmit data register */
};
struct dzregs *dzaddrs[]
{ 0760100, /* address of first dz11 */
};
char speedmap[ 16 ] /* map a Unix speed into a DZ11 equivalent */
{ 000, /* 0 baud */
000, /* 50 baud */
001, /* 75 baud */
002, /* 110 baud */
003, /* 134.5 baud */
004, /* 150 baud */
000, /* dz doesn't support 200 baud */
005, /* 300 baud */
006, /* 600 baud */
007, /* 1200 baud */
010, /* 1800 baud */
012, /* 2400 baud */
014, /* 4800 baud */
016, /* 9600 baud */
000, /* external 1 not supported */
000 /* external 2 not supported */
};
/* definitions for bits in the DZ11 registers */
#define MUXCLR 0000020 /* clear multiplexer in csr */
#define SCENABL 0000040 /* scan enable in csr */
#define IENABLE 0040100 /* xmt & rcv interrupts in csr */
#define RINT 0000200 /* receive done bit in csr */
#define XINT 0100000 /* transmit done bit in csr */
#define LINENUM 0003400 /* line # mask in rcv & csr */
#define PERROR 0010000 /* parity error in rcv */
#define FRERROR 0020000 /* framing error in rcv */
#define OVERRUN 0040000 /* data over run in rcv */
#define BITS_6 0000010 /* six bit characters in lpr */
#define BITS_7 0000020 /* seven bit characters in lpr */
#define BITS_8 0000030 /* eight bit characters in lpr */
#define ONE_SB 0000000 /* one stop bit in lpr */
#define TWO_SB 0000040 /* two stop bits in lpr */
#define PENABLE 0000100 /* parity enabled in lpr */
#define OPAR 0000200 /* odd parity selected in lpr */
#define SSPEED 0000007 /* unix notation for 300 baud */
#define RCV_ON 0010000 /* receiver enable in lpr */
#define DEFAULT 0012470 /* initial parameters for lpr */
/* name:
dzopen and dzclose
function:
open system call routine for the dz11
close system call routine for the dz11
algorithm:
open:
validate the device unit number
get the controller address
if the line isn't already open
initialize the hardware
if modem control is enabled on that line
wait for the line to come up
initialize the software parameters
call ttyopen on it
close:
flush any pending output
mark the line closed
disable further input from that line
parameters:
device designation (major and minor numbers)
flag (whether or not write access is desired)
returns:
a setting of u.u_error if it fails
globals:
dz11 tty tables for the dz11 lines
dzaddrs pointer to the registers
dzmodem
dzcycling
calls:
ttyopen to complete the opening operation
wflushtty to flush the queues
dzparam to set the initial parameters
dzstatus to start modem status cycling
called by:
openi through cdevsw
*/
dzopen( dev , flag )
int dev, flag;
{ register struct dzregs *dzp;
register struct tty *tp;
register int unit;
unit = dev.d_minor;
if (unit >= NDZ11)
then return( u.u_error = ENXIO );
dzp = dzaddrs[ (unit >> 3) ];
tp = &dz11[ unit ];
unit =& 7;
if ((tp->t_state & ISOPEN) == 0) then
{ dzp->dztcr =| (0400 << unit);
dzp->dzcsr =| (SCENABL|IENABLE);
if ( dzmodem[dev.d_minor] ) then
{ spl5();
dzp->dzlpr = unit|DEFAULT;
tp->t_state = WOPEN;
if (~dzcycling)
then dzstatus();
while((tp->t_state & CARR_ON) == 0)
{ sleep( tp, TTIPRI );
if (issig()) then
{ spl0();
psig();
return;
}
}
spl0();
}
tp->t_state =| SSTART|CARR_ON;
tp->t_flags = XTABS|ECHO|CRMOD|EVENP|ODDP;
tp->t_erase = CERASE;
tp->t_kill = CKILL;
tp->t_speeds = SSPEED | (SSPEED << 8);
tp->t_addr = dzstart;
dzparam( dev.d_minor );
}
ttyopen( dev, tp );
}
dzclose( dev, flag )
int dev, flag;
{ register struct tty *tp;
register int unit;
register struct dzregs *dzp;
unit = dev.d_minor;
tp = &dz11[ unit ];
dzp = dzaddrs[ unit >> 3 ];
wflushtty( tp );
tp->t_state = 0;
unit =& 7;
dzp->dzlpr = unit;
dzp->dztcr =& ~(0400 << unit);
}
/* name:
dzread and dzwrite
function:
read system call routine for the dz11
write system call routine for the dz11
algorithm:
convert the minor device designation into a pointer to a tty struct
call the appropriate device independent routine
parameters:
major and minor device designations
globals:
dz11
calls:
ttread
ttwrite
called by:
readi and writei through the cdevsw
*/
dzread( dev )
int dev;
{ register int unit;
register struct tty *tp;
unit = dev.d_minor;
tp = &dz11[ unit ];
ttread( tp );
}
dzwrite( dev )
int dev;
{ register int unit;
register struct tty *tp;
unit = dev.d_minor;
tp = &dz11[ unit ];
ttwrite( tp );
}
/* name:
dzrint
function:
receive interrupt handling routine for the dz11
algorithm:
get a pointer to the registers for the interrupting dz11
while there is data in the silo
get the next character
if from an illegal line,
continue
if a framing error
say the character was a null
call ttyinput with the character
parameters:
dz11 controller number of the interrupting unit
globals:
dz11 tty structures for the dz11 lines
dzaddrs address of dz11 controllers
calls:
ttyinput to process the received characters
called by:
trap
*/
dzrint( unit )
int unit;
{ register struct dzregs *dzp;
register struct tty *tp;
register int c;
int lineno, titp;
dzp = dzaddrs[ unit ];
unit =<< 3;
while((c = dzp->dzrcv) < 0)
{ lineno = ((c & LINENUM) >> 8) + unit;
if (lineno >= NDZ11)
then continue;
tp = &dz11[ lineno ];
if (c & PERROR)
then continue;
if (c & FRERROR)
then c = 0;
else c =& 0377;
if (tp->t_state & ISOPEN)
then ttyinput( c , tp );
else {
if ((titp = tp->t_itp) != 0)
awake(titp,0);
wakeup( tp );
}
}
}
/* name:
dzxint
function:
dz11 transmit interrupt routine
algorithm:
get a pointer to the controller that interrupted
while the dj thinks that I am done with some line
get the line number
get the associated tty structure
if it is timed out, or done disable this line
get the next character
if it is a delay indication, schedule the restart
and disable this line
else set the character up for output
if there is a sleeping writer and the queue has drained some
wake him up
parameters:
the controller number for the dz11 that interrupted
globals:
dz11 pointers to the teletype structures for the dz11 lines
dzaddrs pointers to the dz11 controllers
calls:
wakeup
timeout
called by:
trap
*/
dzxint( unit )
int unit;
{ register struct dzregs *dzp;
register struct tty *tp;
register int lineno;
int c;
dzp = dzaddrs[ unit ];
unit =<< 3;
while( dzp->dzcsr&XINT )
{ lineno = (dzp->dzcsr&LINENUM) >> 8;
tp = &dz11[ lineno + unit ];
if ((tp->t_state&(TIMEOUT|XOFFHNG)) /* agn - XON/XOFF */
|| ((tp->t_state&ISOPEN) == 0))
goto disable;
if ((c = getc( &tp->t_outq )) < 0 )
goto disable;
#ifdef UCLATTY
if (c == CESCAPE)
c = getc( &tp->t_outq );
else
#endif
if (c & 0200)
{ tp->t_state =| TIMEOUT;
if (c =& 0177)
timeout( ttrstrt, tp, c&0177 );
#ifdef UCLATTY
else
tp->t_state =| STOPOUT;
#endif
goto disable;
}
dzp->dztdr = c;
if (tp->t_outq.c_cc <= TTLOWAT)
{ if (tp->t_itp)
awake(tp->t_itp, 0);
if (tp->t_state & ASLEEP)
{ tp->t_state =& ~ASLEEP;
wakeup( &tp->t_outq );
}
}
continue;
disable:
dzp->dztcr =& ~(1 << lineno);
}
dzp->dzcsr =| IENABLE;
}
/* name:
dzstart
function:
to start an output operation on a dz line
algorithm:
if the line is timed out, do nothing
else enable it for transmission
parameters:
pointer to the tty structure for that line
globals:
dzaddrs pointers to addresses of dz11 controllers
dz11 table of tty structures for dz lines
calls:
wakeup to notify a sleeping writer
timeout to schedule resuming output
called by:
dzxint to continue an output operation
ttstart to initiate an output operation
*/
dzstart( atp )
struct tty *atp;
{ register struct dzregs *dzp;
register struct tty *tp;
register int lineno;
tp = atp;
if (tp->t_state&(TIMEOUT|XOFFHNG)) /* agn - XON/XOFF */
then return;
lineno = tp - dz11;
dzp = dzaddrs[ lineno >> 3 ];
lineno =& 7;
dzp->dztcr =| (1 << lineno);
}
/* name:
dzsgtty
function:
dz11 sgtty system call routine
algorithm:
get a pointer to the corresponding tty structure
call ttystty
if anything changed, call dzparam
parameters:
major and minor device designation
argument vector pointer
globals:
dzaddrs addresses of dz11 controllers
calls:
ttystty device independent special function routine
called by:
sgtty (throught cdevsw)
*/
#ifdef UCLATTY
dzsgtty( dev )
int dev;
#endif
#ifndef UCLATTY
dzsgtty( dev , v )
int dev, *v;
#endif
{ register struct tty *tp;
register int unit;
unit = dev.d_minor;
tp = &dz11[ unit ];
#ifdef UCLATTY
if (ttystty( tp ))
#endif
#ifndef UCLATTY
if (ttystty( tp, v ))
#endif
then return;
else dzparam( unit );
}
/* name:
dzparam
function:
DZ11 parameter setting routine
algorithm:
ascertain what controller the specified unit is on
get a pointer to its tty structure
if the speed is set to 0, just turn the line off
else, compute the parametersd
and install them for that line
parameters:
DZ unit number
globals:
dzaddrs to get the controller addresses
dz11 tty structure for the dz lines
called by:
dzopen to initialize the line for the first time
dzsgtty to change parameters
*/
dzparam( unit )
int unit;
{ register struct dzregs *dzp;
register struct tty *tp;
register int parms;
int speed;
dzp = dzaddrs[ unit >> 3 ];
tp = &dz11[ unit ];
unit =& 7;
if (tp->t_speeds == 0) then
{ dzp->dzlpr = unit; /* just turn the line off */
return;
}
else
{ speed = tp->t_speeds&017;
speed = speedmap[ speed ];
}
parms = unit|RCV_ON;
parms =| (speed << 8);
if (tp->t_flags & EVENP) then
if (tp->t_flags & ODDP)
then parms =| BITS_8;
else parms =| (BITS_7|PENABLE);
else parms =| (BITS_7|OPAR|PENABLE);
if (tp->t_speeds.lobyte == 3)
then parms =| TWO_SB;
dzp->dzlpr = parms;
}
/* name:
dzstatus
function:
to see if the lines with modem control enabled still have the
appropriate signals up
algorithm:
For all open lines with modem control enabled,
if the carrier has dropped, send a hangup to the group
if any open lines still have modem control
schedule the next call to dzstatus
else turn off dzcycling
parameters:
none
globals:
dz11
dzmodem
dzcycling
calls:
timeout
called by:
timeout
*/
dzstatus()
{ register int line;
register struct tty *tp;
register struct dzregs *dzp;
int numlines, titp;
numlines = 0;
for( line = 0; line < NDZ11; line++ )
{ dzp = dzaddrs[ line >> 3 ];
tp = &dz11[ line ];
if ((dzmodem[ line ] == 0) || ((tp->t_state&(ISOPEN+WOPEN)) == 0) )
then continue;
numlines++;
if (dzp->dzmsr & (0400 << line)) then
{ tp->t_state =| CARR_ON;
if (tp->t_state&WOPEN) {
if ((titp = tp->t_itp) != 0)
awake(titp,0);
wakeup (tp);
}
}
else
{ tp->t_state =& ~CARR_ON;
if (tp->t_state & ISOPEN)
then signal( tp->t_pgrp, SIGHUP );
}
}
if (numlines) then
{ timeout( &dzstatus, 0, DZRATE );
dzcycling = true;
}
else dzcycling = false;
}
/*
* Await and Capacity routines
*/
/* dzttycap -- capacity for dz tty devices
* Replaced by BBN (dan) 2/3/79: Now calls std ttycap routine
*/
dzttycap(ip, v)
struct inode *ip;
int *v;
{
register struct tty *tp;
extern struct tty dz11[];
tp = &dz11[ip->i_addr[0].d_minor];
ttycap(tp, v);
}
dzttyawt(type, ip, fd)
char type;
struct inode *ip;
int fd;
{
extern char *able();
register struct tty *tp;
tp = &dz11[ip->i_addr[0].d_minor];
tp->t_itp = ablei(type, 0, ip, fd);
}