1 /*
2 * Copyright (c) 1982, 1986 Regents of the University of California.
3 * All rights reserved. The Berkeley software License Agreement
4 * specifies the terms and conditions for redistribution.
5 *
6 * @(#)ct.c 7.6 (Berkeley) 12/16/90
7 */
8
9 #include "ct.h"
10 #if NCT > 0
11 /*
12 * GP DR11C driver used for C/A/T or Autologic APS micro-5
13 */
14 #include "../include/pte.h"
15
16 #include "sys/param.h"
17 #include "sys/systm.h"
18 #include "sys/ioctl.h"
19 #include "sys/tty.h"
20 #include "sys/map.h"
21 #include "sys/buf.h"
22 #include "sys/conf.h"
23 #include "sys/user.h"
24 #include "sys/kernel.h"
25
26 #include "ubareg.h"
27 #include "ubavar.h"
28
29 #define PCAT (PZERO+9)
30 #define CATHIWAT 100
31 #define CATLOWAT 30
32
33 #define REQUEST_B 0x8000
34 #define REQUEST_A 0x80
35 #define INT_ENB_A 0x40
36 #define INT_ENB_B 0x20
37 #define CSR1 0x2
38 #define CSR0 0x1
39
40 struct ct_softc {
41 int sc_state;
42 struct clist sc_oq;
43 } ct_softc[NCT];
44
45 #define CT_OPEN 0x1
46 #define CT_RUNNING 0x2
47
48 struct ctdevice {
49 u_short ctcsr;
50 u_short ctobuf;
51 u_short ctibuf;
52 };
53
54 int ctprobe(), ctattach(), ctintr();
55 struct uba_device *ctdinfo[NCT];
56 u_short ctstd[] = { 0167770, 0 };
57 struct uba_driver ctdriver =
58 { ctprobe, 0, ctattach, 0, ctstd, "ct", ctdinfo };
59
60 #define CTUNIT(dev) (minor(dev))
61
62 int ct_init = 0; /* set to CSR1 for testing loopback on controller */
63
ctprobe(reg)64 ctprobe(reg)
65 caddr_t reg;
66 {
67 register int br, cvec; /* value-result */
68 register struct ctdevice *ctaddr = (struct ctdevice *)reg;
69
70 #ifdef lint
71 br = 0; cvec = br; br = cvec;
72 ctintr(0);
73 #endif
74 /*
75 * There is no way to make a DR11c interrupt without some
76 * external support. We can't always trust that the typesetter
77 * will be online and ready so we've made other provisions.
78 * This probe assumes setting the B Int Enb will generate
79 * an interrupt. To do this, we set CSR0 and loop this back
80 * to REQUEST_B in the second plug on the controller.
81 * Then, we reset the vector to be that for the "real" device.
82 */
83 ctaddr->ctcsr = INT_ENB_B | CSR0; /* Assume hardware loopback! */
84 DELAY(1000);
85 ctaddr->ctcsr = ct_init; /* should be CSR1 for loopback testing */
86 if (cvec & 04) {
87 printf("ct: resetting vector %o to %o\n", cvec, cvec&0773);
88 cvec &= 0773;
89 }
90 return (sizeof (struct ctdevice));
91 }
92
93 /*ARGSUSED*/
94 ctattach(ui)
95 struct uba_device *ui;
96 {
97 }
98
ctopen(dev)99 ctopen(dev)
100 dev_t dev;
101 {
102 register struct ct_softc *sc;
103 register struct uba_device *ui;
104 register struct ctdevice *ctaddr;
105
106 if (CTUNIT(dev) >= NCT || (ui = ctdinfo[CTUNIT(dev)]) == 0 ||
107 ui->ui_alive == 0)
108 return (ENODEV);
109 if ((sc = &ct_softc[CTUNIT(dev)])->sc_state&CT_OPEN)
110 return (EBUSY);
111 sc->sc_state = CT_OPEN;
112 ctaddr = (struct ctdevice *)ui->ui_addr;
113 ctaddr->ctcsr |= INT_ENB_A;
114 return (0);
115 }
116
ctclose(dev)117 ctclose(dev)
118 dev_t dev;
119 {
120 ct_softc[CTUNIT(dev)].sc_state = 0;
121 ctintr(dev);
122 return (0);
123 }
124
ctwrite(dev,uio)125 ctwrite(dev, uio)
126 dev_t dev;
127 struct uio *uio;
128 {
129 register struct ct_softc *sc = &ct_softc[CTUNIT(dev)];
130 register int c;
131 int s, error;
132
133 while ((c = uwritec(uio)) >= 0) {
134 s = spl5();
135 while (sc->sc_oq.c_cc > CATHIWAT)
136 if (error = tsleep((caddr_t)&sc->sc_oq, PCAT | PCATCH,
137 devout, 0))
138 goto out;
139 while (putc(c, &sc->sc_oq) < 0)
140 if (error = tsleep((caddr_t)&lbolt, PCAT | PCATCH,
141 ttybuf, 0))
142 goto out;
143 if ( ! (sc->sc_state & CT_RUNNING) )
144 ctintr(dev);
145 splx(s);
146 }
147 return (0);
148 out:
149 splx(s);
150 return (error);
151 }
152
153 /*
154 * The C/A/T is usually wired to accept data on the .5us DATA_AVAIL strobe.
155 * If you use this with a C/A/T you can remove the lines with "APSu5" below.
156 * This is way out of spec for the Autologic APS micro-5 which requires
157 * at least a 40 microsec strobe. We therefore use CSR1 output as the
158 * "strobe". It is set after data is loaded and reset only in the
159 * interrupt routine. Therefore, the "strobe" is high for adequate time.
160 * The constant "ctdelay" determines the "low" time for the strobe
161 * and may have to be larger on a 780. "2" gives about 10us on a 750.
162 */
163 int ctdelay = 2; /* here so it's visible & changeable */
164
ctintr(dev)165 ctintr(dev)
166 dev_t dev;
167 {
168 register int c;
169 register struct ct_softc *sc = &ct_softc[CTUNIT(dev)];
170 register struct ctdevice *ctaddr =
171 (struct ctdevice *)ctdinfo[CTUNIT(dev)]->ui_addr;
172
173 if ((ctaddr->ctcsr&(INT_ENB_B|REQUEST_B)) == (INT_ENB_B|REQUEST_B)) {
174 ctaddr->ctcsr &= ~(CSR0 | INT_ENB_B); /* set in ctprobe */
175 }
176 if ((ctaddr->ctcsr&(INT_ENB_A|REQUEST_A)) == (INT_ENB_A|REQUEST_A)) {
177 if ((c = getc(&sc->sc_oq)) >= 0) {
178 ctaddr->ctcsr &= ~CSR1; /* APSu5 - drop strobe */
179 ctaddr->ctobuf = c;
180 DELAY(ctdelay); /* APSu5 - pause a bit */
181 ctaddr->ctcsr |= CSR1; /* APSu5 - raise strobe */
182 sc->sc_state |= CT_RUNNING;
183 if (sc->sc_oq.c_cc==0 || sc->sc_oq.c_cc==CATLOWAT)
184 wakeup((caddr_t)&sc->sc_oq);
185 } else if (sc->sc_state == 0) {
186 ctaddr->ctcsr = 0;
187 } else
188 sc->sc_state &= ~CT_RUNNING;
189 }
190 }
191 #endif
192