1f01caa4dSmckusick /*
25e4c29cfSmckusick * Copyright (c) 1982, 1986 Regents of the University of California.
3f01caa4dSmckusick * All rights reserved. The Berkeley software License Agreement
4f01caa4dSmckusick * specifies the terms and conditions for redistribution.
5f01caa4dSmckusick *
6*2ff170e0Sbostic * @(#)vp.c 7.5 (Berkeley) 12/16/90
7f01caa4dSmckusick */
8b177495dSbill
916a40936Swnj #include "vp.h"
107d993dedSbill #if NVP > 0
117d993dedSbill /*
127d993dedSbill * Versatec matrix printer/plotter
137d993dedSbill * dma interface driver
143a2852a0Swnj *
153a2852a0Swnj * SETUP NOTES:
163a2852a0Swnj * Set up both print and plot interrupts to go through the same vector
17dd7ba7e3Skarels * (or kludge probe to reset second vector to first;
18dd7ba7e3Skarels * default 174/200 is already handled).
193a2852a0Swnj * Give the address of the plcsr register in the config specification
207d993dedSbill */
21*2ff170e0Sbostic #include "../include/pte.h"
221a7b9a25Ssam
23*2ff170e0Sbostic #include "sys/param.h"
24*2ff170e0Sbostic #include "sys/user.h"
25*2ff170e0Sbostic #include "sys/buf.h"
26*2ff170e0Sbostic #include "sys/systm.h"
27*2ff170e0Sbostic #include "sys/map.h"
28*2ff170e0Sbostic #include "sys/ioctl.h"
29*2ff170e0Sbostic #include "sys/vcmd.h"
30*2ff170e0Sbostic #include "sys/uio.h"
31*2ff170e0Sbostic #include "sys/kernel.h"
32b177495dSbill
337aac53c4Sbloom #include "ubavar.h"
347aac53c4Sbloom #include "ubareg.h"
35b1c32dd2Sroot
36b177495dSbill unsigned minvpph();
37b177495dSbill
38dd7ba7e3Skarels #define VPPRI (PZERO-1)
39dd7ba7e3Skarels
40dd7ba7e3Skarels struct vpdevice {
41dd7ba7e3Skarels short plbcr;
42dd7ba7e3Skarels short pbxaddr;
43dd7ba7e3Skarels short prbcr;
44dd7ba7e3Skarels u_short pbaddr;
45dd7ba7e3Skarels short plcsr;
46dd7ba7e3Skarels short plbuf;
47dd7ba7e3Skarels short prcsr;
48dd7ba7e3Skarels u_short prbuf;
49dd7ba7e3Skarels };
50dd7ba7e3Skarels
51dd7ba7e3Skarels #define VP_ERROR 0100000
52dd7ba7e3Skarels #define VP_DTCINTR 0040000
53dd7ba7e3Skarels #define VP_DMAACT 0020000
54dd7ba7e3Skarels #define VP_READY 0000200
55dd7ba7e3Skarels #define VP_IENABLE 0000100
56dd7ba7e3Skarels #define VP_TERMCOM 0000040
57dd7ba7e3Skarels #define VP_FFCOM 0000020
58dd7ba7e3Skarels #define VP_EOTCOM 0000010
59dd7ba7e3Skarels #define VP_CLRCOM 0000004
60dd7ba7e3Skarels #define VP_RESET 0000002
61dd7ba7e3Skarels #define VP_SPP 0000001
62dd7ba7e3Skarels
632d065d45Swnj struct vp_softc {
642d065d45Swnj int sc_state;
652d065d45Swnj int sc_count;
66dd7ba7e3Skarels int sc_bufp;
67dd7ba7e3Skarels struct buf *sc_bp;
68dd7ba7e3Skarels int sc_ubinfo;
692d065d45Swnj } vp_softc[NVP];
70b177495dSbill
712d065d45Swnj /* sc_state bits */
72dd7ba7e3Skarels #define VPSC_BUSY 0001000
732d065d45Swnj #define VPSC_MODE 0000700
74dd7ba7e3Skarels #define VPSC_SPP 0000400
75dd7ba7e3Skarels #define VPSC_PLOT 0000200
76dd7ba7e3Skarels #define VPSC_PRINT 0000100
772d065d45Swnj #define VPSC_CMNDS 0000076
78dd7ba7e3Skarels #define VPSC_OPEN 0000001
79b177495dSbill
802d065d45Swnj struct uba_device *vpdinfo[NVP];
81b177495dSbill
822d065d45Swnj #define VPUNIT(dev) (minor(dev))
832d065d45Swnj
842d065d45Swnj struct buf rvpbuf[NVP];
852d065d45Swnj
86dd7ba7e3Skarels int vpprobe(), vpattach();
872d065d45Swnj struct uba_device *vpdinfo[NVP];
882d065d45Swnj u_short vpstd[] = { 0777500, 0 };
892d065d45Swnj struct uba_driver vpdriver =
90dd7ba7e3Skarels { vpprobe, 0, vpattach, 0, vpstd, "vp", vpdinfo };
912d065d45Swnj
vpprobe(reg)922d065d45Swnj vpprobe(reg)
932d065d45Swnj caddr_t reg;
942d065d45Swnj {
952d065d45Swnj register int br, cvec; /* value-result */
962d065d45Swnj register struct vpdevice *vpaddr = (struct vpdevice *)(reg-010);
972d065d45Swnj
98acc57956Swnj #ifdef lint
99acc57956Swnj br = 0; cvec = br; br = cvec;
100acc57956Swnj vpintr(0);
101acc57956Swnj #endif
1022d065d45Swnj vpaddr->prcsr = VP_IENABLE|VP_DTCINTR;
1032d065d45Swnj vpaddr->pbaddr = 0;
1042d065d45Swnj vpaddr->pbxaddr = 0;
1053a2852a0Swnj vpaddr->prbcr = 1;
1062d065d45Swnj DELAY(10000);
1072d065d45Swnj vpaddr->prcsr = 0;
108dd7ba7e3Skarels /* GET INTERRUPT AT SECOND VECTOR BUT WANT FIRST */
1093a2852a0Swnj if (cvec == 0200) {
1103a2852a0Swnj printf("vp reset vec from 200 to 174\n");
1113a2852a0Swnj cvec = 0174;
1123a2852a0Swnj }
1134c931468Skre return (sizeof (struct vpdevice));
1142d065d45Swnj }
1152d065d45Swnj
1162d065d45Swnj /*ARGSUSED*/
1172d065d45Swnj vpattach(ui)
1182d065d45Swnj struct uba_device *ui;
119b177495dSbill {
120b177495dSbill
1212d065d45Swnj ui->ui_addr -= 010;
1222d065d45Swnj ui->ui_physaddr -= 010;
1232d065d45Swnj }
1242d065d45Swnj
vpopen(dev)1252d065d45Swnj vpopen(dev)
1262d065d45Swnj dev_t dev;
1272d065d45Swnj {
1282d065d45Swnj register struct vp_softc *sc;
1292d065d45Swnj register struct vpdevice *vpaddr;
1302d065d45Swnj register struct uba_device *ui;
1312d065d45Swnj
132dd7ba7e3Skarels if (VPUNIT(dev) >= NVP ||
133dd7ba7e3Skarels ((sc = &vp_softc[minor(dev)])->sc_state&VPSC_OPEN) ||
134dd7ba7e3Skarels (ui = vpdinfo[VPUNIT(dev)]) == 0 || ui->ui_alive == 0)
135855a1f9dSroot return (ENXIO);
1362d065d45Swnj vpaddr = (struct vpdevice *)ui->ui_addr;
137dd7ba7e3Skarels sc->sc_state = VPSC_OPEN|VPSC_PRINT | VP_CLRCOM|VP_RESET;
138dd7ba7e3Skarels sc->sc_count = 0;
1392d065d45Swnj vpaddr->prcsr = VP_IENABLE|VP_DTCINTR;
140dd7ba7e3Skarels vptimo(dev);
141dd7ba7e3Skarels while (sc->sc_state & VPSC_CMNDS) {
142dd7ba7e3Skarels (void) spl4();
143dd7ba7e3Skarels if (vpwait(dev)) {
1441db00297Skarels (void) vpclose(dev);
145dd7ba7e3Skarels return (EIO);
146dd7ba7e3Skarels }
147dd7ba7e3Skarels vpstart(dev);
148dd7ba7e3Skarels (void) spl0();
149dd7ba7e3Skarels }
150dd7ba7e3Skarels return (0);
151b177495dSbill }
152b177495dSbill
vpstrategy(bp)153b177495dSbill vpstrategy(bp)
154b177495dSbill register struct buf *bp;
155b177495dSbill {
156dd7ba7e3Skarels register int e;
1572d065d45Swnj register struct vp_softc *sc = &vp_softc[VPUNIT(bp->b_dev)];
1582d065d45Swnj register struct uba_device *ui = vpdinfo[VPUNIT(bp->b_dev)];
1592d065d45Swnj register struct vpdevice *vpaddr = (struct vpdevice *)ui->ui_addr;
160b177495dSbill
161dd7ba7e3Skarels (void) spl4();
162dd7ba7e3Skarels while (sc->sc_state & VPSC_BUSY)
163dd7ba7e3Skarels sleep((caddr_t)sc, VPPRI);
164dd7ba7e3Skarels sc->sc_state |= VPSC_BUSY;
165dd7ba7e3Skarels sc->sc_bp = bp;
166dd7ba7e3Skarels sc->sc_ubinfo = ubasetup(ui->ui_ubanum, bp, UBA_NEEDBDP);
167dd7ba7e3Skarels if (e = vpwait(bp->b_dev))
168dd7ba7e3Skarels goto brkout;
169dd7ba7e3Skarels sc->sc_count = bp->b_bcount;
170dd7ba7e3Skarels vpstart(bp->b_dev);
171dd7ba7e3Skarels while (((sc->sc_state&VPSC_PLOT) ? vpaddr->plcsr : vpaddr->prcsr) & VP_DMAACT)
172dd7ba7e3Skarels sleep((caddr_t)sc, VPPRI);
173dd7ba7e3Skarels sc->sc_count = 0;
174dd7ba7e3Skarels if ((sc->sc_state&VPSC_MODE) == VPSC_SPP)
175dd7ba7e3Skarels sc->sc_state = (sc->sc_state &~ VPSC_MODE) | VPSC_PLOT;
176dd7ba7e3Skarels (void) spl0();
177dd7ba7e3Skarels brkout:
178dd7ba7e3Skarels ubarelse(ui->ui_ubanum, &sc->sc_ubinfo);
179dd7ba7e3Skarels sc->sc_state &= ~VPSC_BUSY;
180dd7ba7e3Skarels sc->sc_bp = 0;
181dd7ba7e3Skarels if (e)
182738f6459Sroot bp->b_flags |= B_ERROR;
183738f6459Sroot iodone(bp);
184dd7ba7e3Skarels wakeup((caddr_t)sc);
185b177495dSbill }
186b177495dSbill
187b177495dSbill int vpblock = 16384;
188b177495dSbill
189b177495dSbill unsigned
minvpph(bp)190b177495dSbill minvpph(bp)
191b177495dSbill struct buf *bp;
192b177495dSbill {
193b177495dSbill
194b177495dSbill if (bp->b_bcount > vpblock)
195b177495dSbill bp->b_bcount = vpblock;
196b177495dSbill }
197b177495dSbill
198b177495dSbill /*ARGSUSED*/
vpwrite(dev,uio)199731660efSroot vpwrite(dev, uio)
2002d065d45Swnj dev_t dev;
201731660efSroot struct uio *uio;
202b177495dSbill {
203b177495dSbill
204ea492ea6Sroot if (VPUNIT(dev) >= NVP)
205731660efSroot return (ENXIO);
206731660efSroot return (physio(vpstrategy, &rvpbuf[VPUNIT(dev)], dev, B_WRITE,
207731660efSroot minvpph, uio));
208b177495dSbill }
209b177495dSbill
vpwait(dev)210dd7ba7e3Skarels vpwait(dev)
211dd7ba7e3Skarels dev_t dev;
212b177495dSbill {
213dd7ba7e3Skarels register struct vpdevice *vpaddr =
214dd7ba7e3Skarels (struct vpdevice *)vpdinfo[VPUNIT(dev)]->ui_addr;
215dd7ba7e3Skarels register struct vp_softc *sc = &vp_softc[VPUNIT(dev)];
216dd7ba7e3Skarels register int e;
217b177495dSbill
218dd7ba7e3Skarels for (;;) {
219dd7ba7e3Skarels e = (sc->sc_state & VPSC_PLOT) ? vpaddr->plcsr : vpaddr->prcsr;
220dd7ba7e3Skarels if (e & (VP_READY|VP_ERROR))
221dd7ba7e3Skarels break;
222dd7ba7e3Skarels sleep((caddr_t)sc, VPPRI);
223dd7ba7e3Skarels }
224dd7ba7e3Skarels /* I WISH I COULD TELL WHETHER AN ERROR INDICATED AN NPR TIMEOUT */
225dd7ba7e3Skarels return (e & VP_ERROR);
2268c5eff05Ssam }
2278c5eff05Ssam
228dd7ba7e3Skarels vpstart(dev)
229dd7ba7e3Skarels dev_t;
2308c5eff05Ssam {
231dd7ba7e3Skarels register struct vp_softc *sc = &vp_softc[VPUNIT(dev)];
232dd7ba7e3Skarels register struct vpdevice *vpaddr =
233dd7ba7e3Skarels (struct vpdevice *)vpdinfo[VPUNIT(dev)]->ui_addr;
234dd7ba7e3Skarels short bit;
2358c5eff05Ssam
2362d065d45Swnj if (sc->sc_count) {
237dd7ba7e3Skarels vpaddr->pbaddr = sc->sc_ubinfo;
238dd7ba7e3Skarels vpaddr->pbxaddr = (sc->sc_ubinfo>>12)&0x30;
239dd7ba7e3Skarels if (sc->sc_state & (VPSC_PRINT|VPSC_SPP))
2402d065d45Swnj vpaddr->prbcr = sc->sc_count;
241b177495dSbill else
2422d065d45Swnj vpaddr->plbcr = sc->sc_count;
243dd7ba7e3Skarels return;
244dd7ba7e3Skarels }
245dd7ba7e3Skarels for (bit = 1; bit != 0; bit <<= 1)
246dd7ba7e3Skarels if (sc->sc_state&bit&VPSC_CMNDS) {
247dd7ba7e3Skarels vpaddr->plcsr |= bit;
248dd7ba7e3Skarels sc->sc_state &= ~bit;
249dd7ba7e3Skarels return;
250b177495dSbill }
251b177495dSbill }
252b177495dSbill
253b177495dSbill /*ARGSUSED*/
vpioctl(dev,cmd,data,flag)254564375aeSsam vpioctl(dev, cmd, data, flag)
255dd7ba7e3Skarels dev_t dev;
256dd7ba7e3Skarels int cmd;
257564375aeSsam register caddr_t data;
258dd7ba7e3Skarels int flag;
259b177495dSbill {
2602d065d45Swnj register struct vp_softc *sc = &vp_softc[VPUNIT(dev)];
261dd7ba7e3Skarels register struct vpdevice *vpaddr =
262dd7ba7e3Skarels (struct vpdevice *)vpdinfo[VPUNIT(dev)]->ui_addr;
263b177495dSbill
264b177495dSbill switch (cmd) {
265b177495dSbill
2662d065d45Swnj case VGETSTATE:
267564375aeSsam *(int *)data = sc->sc_state;
2687be9ed76Skarels return (0);
269b177495dSbill
2702d065d45Swnj case VSETSTATE:
271dd7ba7e3Skarels sc->sc_state =
272dd7ba7e3Skarels (sc->sc_state & ~VPSC_MODE) |
273dd7ba7e3Skarels ((*(int *)data) & (VPSC_MODE|VPSC_CMNDS));
274dd7ba7e3Skarels break;
275b177495dSbill
276b177495dSbill default:
277855a1f9dSroot return (ENOTTY);
278b177495dSbill }
279dd7ba7e3Skarels (void) spl4();
280dd7ba7e3Skarels (void) vpwait(dev);
281dd7ba7e3Skarels if (sc->sc_state&VPSC_SPP)
282dd7ba7e3Skarels vpaddr->plcsr |= VP_SPP;
2838c5eff05Ssam else
284dd7ba7e3Skarels vpaddr->plcsr &= ~VP_SPP;
285dd7ba7e3Skarels sc->sc_count = 0;
286dd7ba7e3Skarels while (sc->sc_state & VPSC_CMNDS) {
287dd7ba7e3Skarels (void) vpwait(dev);
288dd7ba7e3Skarels vpstart(dev);
2898c5eff05Ssam }
290dd7ba7e3Skarels (void) spl0();
291dd7ba7e3Skarels return (0);
2928c5eff05Ssam }
2938c5eff05Ssam
vptimo(dev)2942d065d45Swnj vptimo(dev)
2952d065d45Swnj dev_t dev;
296b177495dSbill {
2972d065d45Swnj register struct vp_softc *sc = &vp_softc[VPUNIT(dev)];
298b177495dSbill
299dd7ba7e3Skarels if (sc->sc_state&VPSC_OPEN)
300dd7ba7e3Skarels timeout(vptimo, (caddr_t)dev, hz/10);
3012d065d45Swnj vpintr(dev);
302b177495dSbill }
303b177495dSbill
304b177495dSbill /*ARGSUSED*/
vpintr(dev)305b177495dSbill vpintr(dev)
3062d065d45Swnj dev_t dev;
307b177495dSbill {
308dd7ba7e3Skarels register struct vp_softc *sc = &vp_softc[VPUNIT(dev)];
309b177495dSbill
310dd7ba7e3Skarels wakeup((caddr_t)sc);
311b177495dSbill }
312b177495dSbill
vpclose(dev)3132d065d45Swnj vpclose(dev)
3142d065d45Swnj dev_t dev;
315b177495dSbill {
3162d065d45Swnj register struct vp_softc *sc = &vp_softc[VPUNIT(dev)];
3172d065d45Swnj register struct vpdevice *vpaddr =
3182d065d45Swnj (struct vpdevice *)vpdinfo[VPUNIT(dev)]->ui_addr;
319b177495dSbill
3202d065d45Swnj sc->sc_state = 0;
321dd7ba7e3Skarels sc->sc_count = 0;
3222d065d45Swnj vpaddr->plcsr = 0;
3231db00297Skarels return (0);
324b177495dSbill }
325bd93d430Sbill
vpreset(uban)3262d065d45Swnj vpreset(uban)
3272d065d45Swnj int uban;
328bd93d430Sbill {
3292d065d45Swnj register int vp11;
330dd7ba7e3Skarels register struct uba_device *ui;
331dd7ba7e3Skarels register struct vp_softc *sc = vp_softc;
3322d065d45Swnj register struct vpdevice *vpaddr;
333bd93d430Sbill
3342d065d45Swnj for (vp11 = 0; vp11 < NVP; vp11++, sc++) {
335dd7ba7e3Skarels if ((ui = vpdinfo[vp11]) == 0 || ui->ui_alive == 0 ||
336dd7ba7e3Skarels ui->ui_ubanum != uban || (sc->sc_state&VPSC_OPEN) == 0)
3372d065d45Swnj continue;
3382d065d45Swnj printf(" vp%d", vp11);
339dd7ba7e3Skarels vpaddr = (struct vpdevice *)ui->ui_addr;
3402d065d45Swnj vpaddr->prcsr = VP_IENABLE|VP_DTCINTR;
341dd7ba7e3Skarels if ((sc->sc_state & VPSC_BUSY) == 0)
342dd7ba7e3Skarels continue;
343dd7ba7e3Skarels sc->sc_ubinfo = 0;
344dd7ba7e3Skarels sc->sc_count = sc->sc_bp->b_bcount;
345dd7ba7e3Skarels vpstart(sc->sc_bp->b_dev);
3462d065d45Swnj }
347bd93d430Sbill }
348bc3f32ddSsam
vpselect()349bc3f32ddSsam vpselect()
350bc3f32ddSsam {
351bc3f32ddSsam return (1);
352bc3f32ddSsam }
3537d993dedSbill #endif
354