# /* 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. */ #include "param.h" #include "conf.h" #include "user.h" #include "tty.h" #define true 0177777 #define false 0000000 #define then /* */ #ifndef NDZ11 #define NDZ11 8 /* default number of DZ lines */ #endif not NDZ11 #ifndef DZADDRS #define DZADDRS 0760100 /* default address of dz registers */ #endif not DZADDRS #ifndef DZMODEM #define DZMODEM 1, 1, 1, 1, 1, 1, 1, 1 /* default modem control enable */ #endif not DZMODEM #define DZRATE 5*HZ /* sample modem status every 5 seconds */ struct tty dz11[ NDZ11 ]; 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[] { DZADDRS }; /* addresses of DZ registers */ /* specification of which lines have modem control enabled */ char dzmodem[ NDZ11 ] /* Setting the i'th entry to a 1 */ { DZMODEM }; /* 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(); 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; 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 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) || ((tp->t_state&ISOPEN) == 0)) then goto disable; if ((c = getc( &tp->t_outq )) < 0 ) then goto disable; #ifdef UCLATTY if (c == CESCAPE) then c = getc( &tp->t_outq ); else #endif if (c & 0200) then { tp->t_state =| TIMEOUT; if (c =& 0177) then timeout( ttrstrt, tp, c&0177 ); #ifdef UCLATTY else tp->t_state =| STOPOUT; #endif goto disable; } dzp->dztdr = c; if ((tp->t_state&ASLEEP) && (tp->t_outq.c_cc <= TTLOWAT)) then { 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) 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; 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&7))) then { tp->t_state =| CARR_ON; if (tp->t_state&WOPEN) then 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; }