USG_PG3/usr/source/io1/dh.c
#
/*
*/
/*
* DH-11 driver
* This driver calls on the DHDM driver.
* If the DH has no DM11-BB, then the latter will
* be fake. To insure loading of the correct DM code,
* lib2 should have dhdm.o, dh.o and dhfdm.o in that order.
*/
#include "../head/param.h"
#include "../head/conf.h"
#include "../head/user.h"
#include "../head/userx.h"
#include "../head/tty.h"
#define DHADDR 0160020
#define DHTYPE 03
#define NDH11 (1*16) /* number of lines */
#define DHNCH 8 /* max number of DMA chars */
struct tty dh11[NDH11];
/*
* Place from which to do DMA on output
*/
char dh_clist[NDH11][DHNCH];
/*
* Used to communicate the number of lines to the DM
*/
int ndh11 {NDH11};
/*
* Hardware control bits
*/
#define BITS6 01
#define BITS7 02
#define BITS8 03
#define TWOSB 04
#define PENABLE 020
/* DEC manuals incorrectly say this bit causes generation of even parity. */
#define OPAR 040
#define HDUPLX 040000
#define IENABLE 030100
#define XINT 0100000
/*
* Software copy of last dhbar
*/
int dhsar[NDH11/16];
struct dhregs {
int dhcsr;
int dhnxch;
int dhlpr;
int dhcar;
int dhbcr;
int dhbar;
int dhbreak;
int dhsilo;
};
/*
* Open a DH11 line.
*/
dhopen(dev, flag)
{
register struct tty *tp;
register minor, dhaddr;
extern dhstart();
if ((minor = dev.d_minor & 0377) >= NDH11) {
u.u_error = ENXIO;
return;
}
dhaddr = DHADDR + (minor>>4)*16;
tp = &dh11[minor];
tp->t_addr = dhstart;
tp->t_dev = dev;
tp->t_dtype = DHTYPE;
tp->t_state =| SSTART;
if (flag) {
dhaddr->dhcsr =| IENABLE;
(*linesw[tp->t_discp].l_open)(dev, tp);
}
}
/*
* Close a DH11 line.
*/
dhclose(dev, flag)
{
register struct tty *tp;
tp = &dh11[dev.d_minor & 0377];
(*linesw[tp->t_discp].l_close)(dev, tp);
}
/*
* Read from a DH11 line.
*/
dhread(dev)
{
register struct tty *tp;
tp = &dh11[dev.d_minor & 0377];
(*linesw[tp->t_discp].l_read)(tp);
}
/*
* write on a DH11 line
*/
dhwrite(dev)
{
register struct tty *tp;
tp = &dh11[dev.d_minor & 0377];
(*linesw[tp->t_discp].l_write)(tp);
}
/*
* DH11 receiver interrupt.
*/
dhrint(dev)
{
register struct tty *tp;
register int c, dhaddr;
dhaddr = DHADDR + (dev*16);
while ((c = dhaddr->dhnxch) < 0) { /* char. present */
tp = &dh11[((c>>8)&017) + dev*16];
if (tp >= &dh11[NDH11])
continue;
c =& (0377|PERROR|FRERROR);
(*linesw[tp->t_discp].l_rcvd)(c, tp);
}
}
/*
* stty/gtty for DH11
*/
dhsgtty(dev, flag)
{
register struct tty *tp;
register minor;
minor = dev.d_minor & 0377;
tp = &dh11[minor];
ttioctl(dev, tp, flag);
}
/*
* Set parameters from open or stty into the DH hardware
* registers.
*/
dhparam(dev, atp)
struct tty *atp;
{
register struct tty *tp;
register int lpr, dhaddr;
int minor, sps;
minor = dev.d_minor & 0377;
dhaddr = DHADDR + (minor>>4)*16;
tp = atp;
sps = PS->integ;
spl5();
dhaddr->dhcsr.lobyte = (minor & 017) | IENABLE;
lpr = (tp->t_speeds.hibyte<<10) | (tp->t_speeds.lobyte<<6);
if (tp->t_speeds.lobyte == 4) /* 134.5 baud */
lpr =| BITS6|PENABLE|HDUPLX;
else if (tp->t_flags&RAW || (tp->t_flags&(ODDP|EVENP))==(ODDP|EVENP))
lpr =| BITS8;
else
lpr =| BITS7|PENABLE;
if ((tp->t_flags&EVENP)==0)
lpr =| OPAR;
if (tp->t_speeds.lobyte == 3) /* 110 baud */
lpr =| TWOSB;
if(tp->t_flags&HDUP)
lpr =| HDUPLX;
dhaddr->dhlpr = lpr;
PS->integ = sps;
}
/*
* 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;
int dhaddr;
dhaddr = DHADDR + (dev*16);
bar = dhsar[dev] & ~dhaddr->dhbar;
dhaddr->dhcsr =& ~XINT;
ttybit = 1;
for (tp = &dh11[dev*16]; bar; tp++) {
if(bar&ttybit) {
dhsar[dev] =& ~ttybit;
bar =& ~ttybit;
tp->t_state =& ~BUSY;
dhstart(tp);
}
ttybit =<< 1;
}
}
/*
* Start (restart) transmission on the given DH11 line.
*/
dhstart(atp)
struct tty *atp;
{
extern ttrstrt();
register c, nch;
register struct tty *tp;
int sps, dev, dhaddr;
char *cp;
sps = PS->integ;
spl5();
tp = atp;
dev = tp-dh11;
dhaddr = DHADDR + (dev>>4)*16;
/*
* If it's currently active, or delaying,
* no need to do anything.
*/
if (tp->t_state&(TIMEOUT|BUSY))
goto out;
/*
* t_char is a delay indicator which may have been
* left over from the last start.
* Arrange for the delay.
*/
if (c = tp->t_char) {
tp->t_char = 0;
timeout(ttrstrt, tp, (c&0177)+6);
tp->t_state =| TIMEOUT;
goto out;
}
cp = dh_clist[dev.d_minor & 0377];
nch = 0;
/*
* Copy DHNCH characters, or up to a delay indicator,
* to the DMA area.
*/
while (nch > -DHNCH && (c = (*linesw[tp->t_discp].l_xmtd)(tp))) {
if (c & CTOUT) {
tp->t_char = c & 0377;
break;
}
*cp++ = c & 0377;
nch--;
}
/*
* If any characters were set up, start transmission;
* otherwise, check for possible delay.
*/
if (nch) {
dhaddr->dhcsr.lobyte = (dev.d_minor & 017) | IENABLE;
dhaddr->dhcar = cp+nch;
dhaddr->dhbcr = nch;
c = 1<<(dev.d_minor & 017);
dhaddr->dhbar =| c;
dhsar[dev>>4] =| c;
tp->t_state =| BUSY;
} else if (c = tp->t_char) {
tp->t_char = 0;
timeout(ttrstrt, tp, (c&0177)+6);
tp->t_state =| TIMEOUT;
}
out:
PS->integ = sps;
}