from computer center; changed #includes and EBUSY if open
[unix-history] / usr / src / sys / vax / uba / ct.c
/*
* Copyright (c) 1982 Regents of the University of California.
* All rights reserved. The Berkeley software License Agreement
* specifies the terms and conditions for redistribution.
*
* @(#)ct.c 6.4 (Berkeley) %G%
*/
#include "ct.h"
#if NCT > 0
/*
* GP DR11C driver used for C/A/T or Autologic APS micro-5
*/
#include "../machine/pte.h"
#include "param.h"
#include "systm.h"
#include "tty.h"
#include "map.h"
#include "buf.h"
#include "conf.h"
#include "dir.h"
#include "user.h"
#include "kernel.h"
#include "ubareg.h"
#include "ubavar.h"
#define PCAT (PZERO+9)
#define CATHIWAT 100
#define CATLOWAT 30
#define REQUEST_B 0x8000
#define REQUEST_A 0x80
#define INT_ENB_A 0x40
#define INT_ENB_B 0x20
#define CSR1 0x2
#define CSR0 0x1
struct ct_softc {
int sc_state;
struct clist sc_oq;
} ct_softc[NCT];
#define CT_OPEN 0x1
#define CT_RUNNING 0x2
struct ctdevice {
u_short ctcsr;
u_short ctobuf;
u_short ctibuf;
};
int ctprobe(), ctattach(), ctintr();
struct uba_device *ctdinfo[NCT];
u_short ctstd[] = { 0167770, 0 };
struct uba_driver ctdriver =
{ ctprobe, 0, ctattach, 0, ctstd, "ct", ctdinfo };
#define CTUNIT(dev) (minor(dev))
int ct_init = 0; /* set to CSR1 for testing loopback on controller */
ctprobe(reg)
caddr_t reg;
{
register int br, cvec; /* value-result */
register struct ctdevice *ctaddr = (struct ctdevice *)reg;
#ifdef lint
br = 0; cvec = br; br = cvec;
ctintr(0);
#endif
/*
* There is no way to make a DR11c interrupt without some
* external support. We can't always trust that the typesetter
* will be online and ready so we've made other provisions.
* This probe assumes setting the B Int Enb will generate
* an interrupt. To do this, we set CSR0 and loop this back
* to REQUEST_B in the second plug on the controller.
* Then, we reset the vector to be that for the "real" device.
*/
ctaddr->ctcsr = INT_ENB_B | CSR0; /* Assume hardware loopback! */
DELAY(1000);
ctaddr->ctcsr = ct_init; /* should be CSR1 for loopback testing */
if (cvec & 04) {
printf("ct: resetting vector %o to %o\n", cvec, cvec&0773);
cvec &= 0773;
}
return (sizeof (struct ctdevice));
}
/*ARGSUSED*/
ctattach(ui)
register struct uba_device *ui;
{
}
ctopen(dev)
dev_t dev;
{
register struct ct_softc *sc;
register struct uba_device *ui;
register struct ctdevice *ctaddr;
if (CTUNIT(dev) >= NCT || (ui = ctdinfo[CTUNIT(dev)]) == 0 ||
ui->ui_alive == 0)
return (ENODEV);
if ((sc = &ct_softc[CTUNIT(dev)])->sc_state&CT_OPEN)
return (EBUSY);
sc->sc_state = CT_OPEN;
ctaddr = (struct ctdevice *)ui->ui_addr;
ctaddr->ctcsr |= INT_ENB_A;
return (0);
}
ctclose(dev)
dev_t dev;
{
ct_softc[CTUNIT(dev)].sc_state = 0;
ctintr(dev);
return (0);
}
ctwrite(dev, uio)
dev_t dev;
struct uio *uio;
{
register struct ct_softc *sc = &ct_softc[CTUNIT(dev)];
register int c;
int s;
while ((c = uwritec(uio)) >= 0) {
s = spl5();
while (sc->sc_oq.c_cc > CATHIWAT)
sleep((caddr_t)&sc->sc_oq, PCAT);
while (putc(c, &sc->sc_oq) < 0)
sleep((caddr_t)&lbolt, PCAT);
if ( ! (sc->sc_state & CT_RUNNING) )
ctintr(dev);
splx(s);
}
return (0);
}
/*
* The C/A/T is usually wired to accept data on the .5us DATA_AVAIL strobe.
* If you use this with a C/A/T you can remove the lines with "APSu5" below.
* This is way out of spec for the Autologic APS micro-5 which requires
* at least a 40 microsec strobe. We therefore use CSR1 output as the
* "strobe". It is set after data is loaded and reset only in the
* interrupt routine. Therefore, the "strobe" is high for adequate time.
* The constant "ctdelay" determines the "low" time for the strobe
* and may have to be larger on a 780. "2" gives about 10us on a 750.
*/
int ctdelay = 2; /* here so it's visible & changeable */
ctintr(dev)
dev_t dev;
{
register int c;
register struct ct_softc *sc = &ct_softc[CTUNIT(dev)];
register struct ctdevice *ctaddr =
(struct ctdevice *)ctdinfo[CTUNIT(dev)]->ui_addr;
if ((ctaddr->ctcsr&(INT_ENB_B|REQUEST_B)) == (INT_ENB_B|REQUEST_B)) {
ctaddr->ctcsr &= ~(CSR0 | INT_ENB_B); /* set in ctprobe */
}
if ((ctaddr->ctcsr&(INT_ENB_A|REQUEST_A)) == (INT_ENB_A|REQUEST_A)) {
if ((c = getc(&sc->sc_oq)) >= 0) {
ctaddr->ctcsr &= ~CSR1; /* APSu5 - drop strobe */
ctaddr->ctobuf = c;
DELAY(ctdelay); /* APSu5 - pause a bit */
ctaddr->ctcsr |= CSR1; /* APSu5 - raise strobe */
sc->sc_state |= CT_RUNNING;
if (sc->sc_oq.c_cc==0 || sc->sc_oq.c_cc==CATLOWAT)
wakeup(&sc->sc_oq);
} else if (sc->sc_state == 0) {
ctaddr->ctcsr = 0;
} else
sc->sc_state &= ~CT_RUNNING;
}
}
#endif