1a7d36711Smckusick /*
2ca77bbffSmckusick * Copyright (c) 1982, 1986 Regents of the University of California.
3a7d36711Smckusick * All rights reserved. The Berkeley software License Agreement
4a7d36711Smckusick * specifies the terms and conditions for redistribution.
5a7d36711Smckusick *
6*39bdaf89Sbostic * @(#)ct.c 7.6 (Berkeley) 12/16/90
7a7d36711Smckusick */
8a3f0d044Swnj
98ff17834Swnj #include "ct.h"
10a3f0d044Swnj #if NCT > 0
11a3f0d044Swnj /*
123b27d6b7Skarels * GP DR11C driver used for C/A/T or Autologic APS micro-5
13a3f0d044Swnj */
14*39bdaf89Sbostic #include "../include/pte.h"
15a3f0d044Swnj
16*39bdaf89Sbostic #include "sys/param.h"
17*39bdaf89Sbostic #include "sys/systm.h"
18*39bdaf89Sbostic #include "sys/ioctl.h"
19*39bdaf89Sbostic #include "sys/tty.h"
20*39bdaf89Sbostic #include "sys/map.h"
21*39bdaf89Sbostic #include "sys/buf.h"
22*39bdaf89Sbostic #include "sys/conf.h"
23*39bdaf89Sbostic #include "sys/user.h"
24*39bdaf89Sbostic #include "sys/kernel.h"
25a3f0d044Swnj
26146803c9Sbloom #include "ubareg.h"
27146803c9Sbloom #include "ubavar.h"
28f65a77c3Sroot
29a3f0d044Swnj #define PCAT (PZERO+9)
30a3f0d044Swnj #define CATHIWAT 100
31a3f0d044Swnj #define CATLOWAT 30
32a3f0d044Swnj
333b27d6b7Skarels #define REQUEST_B 0x8000
343b27d6b7Skarels #define REQUEST_A 0x80
353b27d6b7Skarels #define INT_ENB_A 0x40
363b27d6b7Skarels #define INT_ENB_B 0x20
373b27d6b7Skarels #define CSR1 0x2
383b27d6b7Skarels #define CSR0 0x1
393b27d6b7Skarels
408ff17834Swnj struct ct_softc {
413b27d6b7Skarels int sc_state;
428ff17834Swnj struct clist sc_oq;
438ff17834Swnj } ct_softc[NCT];
44a3f0d044Swnj
453b27d6b7Skarels #define CT_OPEN 0x1
463b27d6b7Skarels #define CT_RUNNING 0x2
473b27d6b7Skarels
488ff17834Swnj struct ctdevice {
493b27d6b7Skarels u_short ctcsr;
503b27d6b7Skarels u_short ctobuf;
513b27d6b7Skarels u_short ctibuf;
52a3f0d044Swnj };
53a3f0d044Swnj
548ff17834Swnj int ctprobe(), ctattach(), ctintr();
558ff17834Swnj struct uba_device *ctdinfo[NCT];
563b27d6b7Skarels u_short ctstd[] = { 0167770, 0 };
578ff17834Swnj struct uba_driver ctdriver =
588ff17834Swnj { ctprobe, 0, ctattach, 0, ctstd, "ct", ctdinfo };
59a3f0d044Swnj
608ac36657Swnj #define CTUNIT(dev) (minor(dev))
618ac36657Swnj
623b27d6b7Skarels int ct_init = 0; /* set to CSR1 for testing loopback on controller */
633b27d6b7Skarels
ctprobe(reg)648ff17834Swnj ctprobe(reg)
658ff17834Swnj caddr_t reg;
66a3f0d044Swnj {
673b9ff7f8Sbugs register int br, cvec; /* value-result */
688ff17834Swnj register struct ctdevice *ctaddr = (struct ctdevice *)reg;
698ff17834Swnj
704f5d781bSwnj #ifdef lint
714f5d781bSwnj br = 0; cvec = br; br = cvec;
724f5d781bSwnj ctintr(0);
734f5d781bSwnj #endif
743b27d6b7Skarels /*
753b27d6b7Skarels * There is no way to make a DR11c interrupt without some
763b27d6b7Skarels * external support. We can't always trust that the typesetter
773b27d6b7Skarels * will be online and ready so we've made other provisions.
783b27d6b7Skarels * This probe assumes setting the B Int Enb will generate
793b27d6b7Skarels * an interrupt. To do this, we set CSR0 and loop this back
803b27d6b7Skarels * to REQUEST_B in the second plug on the controller.
813b27d6b7Skarels * Then, we reset the vector to be that for the "real" device.
823b27d6b7Skarels */
833b27d6b7Skarels ctaddr->ctcsr = INT_ENB_B | CSR0; /* Assume hardware loopback! */
843b27d6b7Skarels DELAY(1000);
853b27d6b7Skarels ctaddr->ctcsr = ct_init; /* should be CSR1 for loopback testing */
863b27d6b7Skarels if (cvec & 04) {
873b27d6b7Skarels printf("ct: resetting vector %o to %o\n", cvec, cvec&0773);
883b27d6b7Skarels cvec &= 0773;
893b27d6b7Skarels }
90d2841364Skre return (sizeof (struct ctdevice));
91a3f0d044Swnj }
92a3f0d044Swnj
938ac36657Swnj /*ARGSUSED*/
948ac36657Swnj ctattach(ui)
956a131df8Skarels struct uba_device *ui;
968ac36657Swnj {
978ac36657Swnj }
988ac36657Swnj
ctopen(dev)998ff17834Swnj ctopen(dev)
1008ff17834Swnj dev_t dev;
101a3f0d044Swnj {
1028ff17834Swnj register struct ct_softc *sc;
1038ff17834Swnj register struct uba_device *ui;
1048ff17834Swnj register struct ctdevice *ctaddr;
1058ff17834Swnj
1068ff17834Swnj if (CTUNIT(dev) >= NCT || (ui = ctdinfo[CTUNIT(dev)]) == 0 ||
1073b27d6b7Skarels ui->ui_alive == 0)
1083b27d6b7Skarels return (ENODEV);
1093b27d6b7Skarels if ((sc = &ct_softc[CTUNIT(dev)])->sc_state&CT_OPEN)
1103b27d6b7Skarels return (EBUSY);
1113b27d6b7Skarels sc->sc_state = CT_OPEN;
1123b27d6b7Skarels ctaddr = (struct ctdevice *)ui->ui_addr;
1133b27d6b7Skarels ctaddr->ctcsr |= INT_ENB_A;
1140015c898Sroot return (0);
1158ff17834Swnj }
1168ff17834Swnj
ctclose(dev)1178ff17834Swnj ctclose(dev)
1188ff17834Swnj dev_t dev;
1198ff17834Swnj {
1203b27d6b7Skarels ct_softc[CTUNIT(dev)].sc_state = 0;
1218ff17834Swnj ctintr(dev);
1223b27d6b7Skarels return (0);
123a3f0d044Swnj }
124a3f0d044Swnj
ctwrite(dev,uio)125f6034122Sroot ctwrite(dev, uio)
1268ff17834Swnj dev_t dev;
127f6034122Sroot struct uio *uio;
128a3f0d044Swnj {
1298ff17834Swnj register struct ct_softc *sc = &ct_softc[CTUNIT(dev)];
1308ff17834Swnj register int c;
1311db00297Skarels int s, error;
132a3f0d044Swnj
1333b27d6b7Skarels while ((c = uwritec(uio)) >= 0) {
1343b27d6b7Skarels s = spl5();
1358ff17834Swnj while (sc->sc_oq.c_cc > CATHIWAT)
1361db00297Skarels if (error = tsleep((caddr_t)&sc->sc_oq, PCAT | PCATCH,
1371db00297Skarels devout, 0))
1381db00297Skarels goto out;
1398ff17834Swnj while (putc(c, &sc->sc_oq) < 0)
1401db00297Skarels if (error = tsleep((caddr_t)&lbolt, PCAT | PCATCH,
1411db00297Skarels ttybuf, 0))
1421db00297Skarels goto out;
1433b27d6b7Skarels if ( ! (sc->sc_state & CT_RUNNING) )
1448ff17834Swnj ctintr(dev);
1453b27d6b7Skarels splx(s);
146a3f0d044Swnj }
1473b27d6b7Skarels return (0);
1481db00297Skarels out:
1491db00297Skarels splx(s);
1501db00297Skarels return (error);
151a3f0d044Swnj }
152a3f0d044Swnj
1533b27d6b7Skarels /*
1543b27d6b7Skarels * The C/A/T is usually wired to accept data on the .5us DATA_AVAIL strobe.
1553b27d6b7Skarels * If you use this with a C/A/T you can remove the lines with "APSu5" below.
1563b27d6b7Skarels * This is way out of spec for the Autologic APS micro-5 which requires
1573b27d6b7Skarels * at least a 40 microsec strobe. We therefore use CSR1 output as the
1583b27d6b7Skarels * "strobe". It is set after data is loaded and reset only in the
1593b27d6b7Skarels * interrupt routine. Therefore, the "strobe" is high for adequate time.
1603b27d6b7Skarels * The constant "ctdelay" determines the "low" time for the strobe
1613b27d6b7Skarels * and may have to be larger on a 780. "2" gives about 10us on a 750.
1623b27d6b7Skarels */
1633b27d6b7Skarels int ctdelay = 2; /* here so it's visible & changeable */
1643b27d6b7Skarels
ctintr(dev)1658ff17834Swnj ctintr(dev)
1668ff17834Swnj dev_t dev;
167a3f0d044Swnj {
168a3f0d044Swnj register int c;
1698ff17834Swnj register struct ct_softc *sc = &ct_softc[CTUNIT(dev)];
1708ff17834Swnj register struct ctdevice *ctaddr =
1718ff17834Swnj (struct ctdevice *)ctdinfo[CTUNIT(dev)]->ui_addr;
172a3f0d044Swnj
1733b27d6b7Skarels if ((ctaddr->ctcsr&(INT_ENB_B|REQUEST_B)) == (INT_ENB_B|REQUEST_B)) {
1743b27d6b7Skarels ctaddr->ctcsr &= ~(CSR0 | INT_ENB_B); /* set in ctprobe */
1753b27d6b7Skarels }
1763b27d6b7Skarels if ((ctaddr->ctcsr&(INT_ENB_A|REQUEST_A)) == (INT_ENB_A|REQUEST_A)) {
1778ff17834Swnj if ((c = getc(&sc->sc_oq)) >= 0) {
1783b27d6b7Skarels ctaddr->ctcsr &= ~CSR1; /* APSu5 - drop strobe */
1793b27d6b7Skarels ctaddr->ctobuf = c;
1803b27d6b7Skarels DELAY(ctdelay); /* APSu5 - pause a bit */
1813b27d6b7Skarels ctaddr->ctcsr |= CSR1; /* APSu5 - raise strobe */
1823b27d6b7Skarels sc->sc_state |= CT_RUNNING;
1838ff17834Swnj if (sc->sc_oq.c_cc==0 || sc->sc_oq.c_cc==CATLOWAT)
1846a131df8Skarels wakeup((caddr_t)&sc->sc_oq);
1853b27d6b7Skarels } else if (sc->sc_state == 0) {
1868ff17834Swnj ctaddr->ctcsr = 0;
1873b27d6b7Skarels } else
1883b27d6b7Skarels sc->sc_state &= ~CT_RUNNING;
189a3f0d044Swnj }
190a3f0d044Swnj }
191a3f0d044Swnj #endif
192