Commit | Line | Data |
---|---|---|
60f56dfc | 1 | /* |
030a8056 KB |
2 | * Copyright (c) 1982, 1990, 1993 |
3 | * The Regents of the University of California. All rights reserved. | |
60f56dfc KM |
4 | * |
5 | * %sccs.include.redist.c% | |
6 | * | |
030a8056 | 7 | * @(#)fhpib.c 8.1 (Berkeley) %G% |
60f56dfc KM |
8 | */ |
9 | ||
10 | /* | |
11 | * 98625A/B HPIB driver | |
12 | */ | |
13 | #include "hpib.h" | |
14 | #if NHPIB > 0 | |
15 | ||
38a01dbe KB |
16 | #include <sys/param.h> |
17 | #include <sys/systm.h> | |
18 | #include <sys/buf.h> | |
19 | ||
20 | #include <hp/dev/device.h> | |
21 | ||
22 | #include <hp300/dev/fhpibreg.h> | |
23 | #include <hp300/dev/hpibvar.h> | |
24 | #include <hp300/dev/dmavar.h> | |
60f56dfc KM |
25 | |
26 | /* | |
27 | * Inline version of fhpibwait to be used in places where | |
28 | * we don't worry about getting hung. | |
29 | */ | |
da1e0abb | 30 | #define FHPIBWAIT(hd, m) while (((hd)->hpib_intr & (m)) == 0) DELAY(1) |
60f56dfc KM |
31 | |
32 | #ifdef DEBUG | |
33 | int fhpibdebugunit = -1; | |
34 | int fhpibdebug = 0; | |
35 | #define FDB_FAIL 0x01 | |
36 | #define FDB_DMA 0x02 | |
37 | #define FDB_WAIT 0x04 | |
38 | #define FDB_PPOLL 0x08 | |
39 | ||
40 | int dopriodma = 0; /* use high priority DMA */ | |
41 | int doworddma = 1; /* non-zero if we should attempt word dma */ | |
60f56dfc | 42 | int doppollint = 1; /* use ppoll interrupts instead of watchdog */ |
9acfa6cd | 43 | int fhpibppolldelay = 50; |
60f56dfc KM |
44 | |
45 | long fhpibbadint[2] = { 0 }; | |
46 | long fhpibtransfer[NHPIB] = { 0 }; | |
47 | long fhpibnondma[NHPIB] = { 0 }; | |
48 | long fhpibworddma[NHPIB] = { 0 }; | |
9acfa6cd | 49 | long fhpibppollfail[NHPIB] = { 0 }; |
60f56dfc KM |
50 | #endif |
51 | ||
52 | int fhpibcmd[NHPIB]; | |
60f56dfc KM |
53 | |
54 | fhpibtype(hc) | |
55 | register struct hp_ctlr *hc; | |
56 | { | |
57 | register struct hpib_softc *hs = &hpib_softc[hc->hp_unit]; | |
58 | register struct fhpibdevice *hd = (struct fhpibdevice *)hc->hp_addr; | |
59 | ||
60 | if (hd->hpib_cid != HPIBC) | |
61 | return(0); | |
62 | hs->sc_type = HPIBC; | |
63 | hs->sc_ba = HPIBC_BA; | |
64 | hc->hp_ipl = HPIB_IPL(hd->hpib_ids); | |
65 | return(1); | |
66 | } | |
67 | ||
68 | fhpibreset(unit) | |
69 | { | |
70 | register struct hpib_softc *hs = &hpib_softc[unit]; | |
71 | register struct fhpibdevice *hd; | |
72 | ||
73 | hd = (struct fhpibdevice *)hs->sc_hc->hp_addr; | |
74 | hd->hpib_cid = 0xFF; | |
75 | DELAY(100); | |
76 | hd->hpib_cmd = CT_8BIT; | |
77 | hd->hpib_ar = AR_ARONC; | |
78 | fhpibifc(hd); | |
79 | hd->hpib_ie = IDS_IE; | |
80 | hd->hpib_data = C_DCL; | |
81 | DELAY(100000); | |
82 | /* | |
83 | * See if we can do word dma. | |
84 | * If so, we should be able to write and read back the appropos bit. | |
85 | */ | |
86 | hd->hpib_ie |= IDS_WDMA; | |
87 | if (hd->hpib_ie & IDS_WDMA) { | |
88 | hd->hpib_ie &= ~IDS_WDMA; | |
89 | hs->sc_flags |= HPIBF_DMA16; | |
90 | #ifdef DEBUG | |
91 | if (fhpibdebug & FDB_DMA) | |
92 | printf("fhpibtype: unit %d has word dma\n", unit); | |
93 | ||
94 | #endif | |
95 | } | |
96 | } | |
97 | ||
98 | fhpibifc(hd) | |
99 | register struct fhpibdevice *hd; | |
100 | { | |
101 | hd->hpib_cmd |= CT_IFC; | |
102 | hd->hpib_cmd |= CT_INITFIFO; | |
103 | DELAY(100); | |
104 | hd->hpib_cmd &= ~CT_IFC; | |
105 | hd->hpib_cmd |= CT_REN; | |
106 | hd->hpib_stat = ST_ATN; | |
107 | } | |
108 | ||
da1e0abb | 109 | fhpibsend(unit, slave, sec, addr, origcnt) |
60f56dfc | 110 | register char *addr; |
60f56dfc KM |
111 | { |
112 | register struct hpib_softc *hs = &hpib_softc[unit]; | |
113 | register struct fhpibdevice *hd; | |
da1e0abb | 114 | register int cnt = origcnt; |
60f56dfc | 115 | register int timo; |
60f56dfc KM |
116 | |
117 | hd = (struct fhpibdevice *)hs->sc_hc->hp_addr; | |
118 | hd->hpib_stat = 0; | |
119 | hd->hpib_imask = IM_IDLE | IM_ROOM; | |
120 | if (fhpibwait(hd, IM_IDLE) < 0) | |
da1e0abb | 121 | goto senderr; |
60f56dfc KM |
122 | hd->hpib_stat = ST_ATN; |
123 | hd->hpib_data = C_UNL; | |
124 | hd->hpib_data = C_TAG + hs->sc_ba; | |
125 | hd->hpib_data = C_LAG + slave; | |
126 | if (sec != -1) | |
127 | hd->hpib_data = C_SCG + sec; | |
128 | if (fhpibwait(hd, IM_IDLE) < 0) | |
da1e0abb KM |
129 | goto senderr; |
130 | if (cnt) { | |
131 | hd->hpib_stat = ST_WRITE; | |
60f56dfc KM |
132 | while (--cnt) { |
133 | hd->hpib_data = *addr++; | |
134 | timo = hpibtimeout; | |
da1e0abb KM |
135 | while ((hd->hpib_intr & IM_ROOM) == 0) { |
136 | if (--timo <= 0) | |
137 | goto senderr; | |
138 | DELAY(1); | |
139 | } | |
60f56dfc KM |
140 | } |
141 | hd->hpib_stat = ST_EOI; | |
142 | hd->hpib_data = *addr; | |
143 | FHPIBWAIT(hd, IM_ROOM); | |
144 | hd->hpib_stat = ST_ATN; | |
145 | /* XXX: HP-UX claims bug with CS80 transparent messages */ | |
146 | if (sec == 0x12) | |
147 | DELAY(150); | |
148 | hd->hpib_data = C_UNL; | |
da1e0abb | 149 | (void) fhpibwait(hd, IM_IDLE); |
60f56dfc | 150 | } |
da1e0abb KM |
151 | hd->hpib_imask = 0; |
152 | return (origcnt); | |
153 | senderr: | |
154 | hd->hpib_imask = 0; | |
155 | fhpibifc(hd); | |
60f56dfc | 156 | #ifdef DEBUG |
da1e0abb KM |
157 | if (fhpibdebug & FDB_FAIL) { |
158 | printf("hpib%d: fhpibsend failed: slave %d, sec %x, ", | |
159 | unit, slave, sec); | |
160 | printf("sent %d of %d bytes\n", origcnt-cnt-1, origcnt); | |
60f56dfc | 161 | } |
da1e0abb KM |
162 | #endif |
163 | return(origcnt - cnt - 1); | |
60f56dfc KM |
164 | } |
165 | ||
da1e0abb | 166 | fhpibrecv(unit, slave, sec, addr, origcnt) |
60f56dfc | 167 | register char *addr; |
60f56dfc KM |
168 | { |
169 | register struct hpib_softc *hs = &hpib_softc[unit]; | |
170 | register struct fhpibdevice *hd; | |
da1e0abb | 171 | register int cnt = origcnt; |
60f56dfc | 172 | register int timo; |
60f56dfc KM |
173 | |
174 | hd = (struct fhpibdevice *)hs->sc_hc->hp_addr; | |
175 | hd->hpib_stat = 0; | |
176 | hd->hpib_imask = IM_IDLE | IM_ROOM | IM_BYTE; | |
177 | if (fhpibwait(hd, IM_IDLE) < 0) | |
da1e0abb | 178 | goto recverror; |
60f56dfc KM |
179 | hd->hpib_stat = ST_ATN; |
180 | hd->hpib_data = C_UNL; | |
181 | hd->hpib_data = C_LAG + hs->sc_ba; | |
182 | hd->hpib_data = C_TAG + slave; | |
183 | if (sec != -1) | |
184 | hd->hpib_data = C_SCG + sec; | |
185 | if (fhpibwait(hd, IM_IDLE) < 0) | |
da1e0abb | 186 | goto recverror; |
60f56dfc KM |
187 | hd->hpib_stat = ST_READ0; |
188 | hd->hpib_data = 0; | |
da1e0abb KM |
189 | if (cnt) { |
190 | while (--cnt >= 0) { | |
60f56dfc | 191 | timo = hpibtimeout; |
da1e0abb KM |
192 | while ((hd->hpib_intr & IM_BYTE) == 0) { |
193 | if (--timo == 0) | |
194 | goto recvbyteserror; | |
195 | DELAY(1); | |
196 | } | |
60f56dfc | 197 | *addr++ = hd->hpib_data; |
da1e0abb | 198 | } |
60f56dfc KM |
199 | FHPIBWAIT(hd, IM_ROOM); |
200 | hd->hpib_stat = ST_ATN; | |
201 | hd->hpib_data = (slave == 31) ? C_UNA : C_UNT; | |
da1e0abb | 202 | (void) fhpibwait(hd, IM_IDLE); |
60f56dfc | 203 | } |
da1e0abb KM |
204 | hd->hpib_imask = 0; |
205 | return (origcnt); | |
206 | ||
207 | recverror: | |
208 | fhpibifc(hd); | |
209 | recvbyteserror: | |
210 | hd->hpib_imask = 0; | |
60f56dfc | 211 | #ifdef DEBUG |
da1e0abb KM |
212 | if (fhpibdebug & FDB_FAIL) { |
213 | printf("hpib%d: fhpibrecv failed: slave %d, sec %x, ", | |
214 | unit, slave, sec); | |
215 | printf("got %d of %d bytes\n", origcnt-cnt-1, origcnt); | |
60f56dfc | 216 | } |
da1e0abb KM |
217 | #endif |
218 | return(origcnt - cnt - 1); | |
60f56dfc KM |
219 | } |
220 | ||
221 | fhpibgo(unit, slave, sec, addr, count, rw) | |
222 | register int unit; | |
223 | char *addr; | |
224 | { | |
225 | register struct hpib_softc *hs = &hpib_softc[unit]; | |
226 | register struct fhpibdevice *hd; | |
227 | register int i; | |
228 | int flags = 0; | |
229 | ||
230 | #ifdef lint | |
231 | i = unit; if (i) return; | |
232 | #endif | |
233 | hd = (struct fhpibdevice *)hs->sc_hc->hp_addr; | |
234 | hs->sc_flags |= HPIBF_IO; | |
235 | if (rw == B_READ) | |
236 | hs->sc_flags |= HPIBF_READ; | |
237 | #ifdef DEBUG | |
238 | else if (hs->sc_flags & HPIBF_READ) { | |
239 | printf("fhpibgo: HPIBF_READ still set\n"); | |
240 | hs->sc_flags &= ~HPIBF_READ; | |
241 | } | |
242 | #endif | |
243 | hs->sc_count = count; | |
244 | hs->sc_addr = addr; | |
245 | #ifdef DEBUG | |
246 | fhpibtransfer[unit]++; | |
247 | #endif | |
248 | if ((hs->sc_flags & HPIBF_DMA16) && | |
249 | ((int)addr & 1) == 0 && count && (count & 1) == 0 | |
250 | #ifdef DEBUG | |
251 | && doworddma | |
252 | #endif | |
253 | ) { | |
254 | #ifdef DEBUG | |
255 | fhpibworddma[unit]++; | |
256 | #endif | |
257 | flags |= DMAGO_WORD; | |
258 | hd->hpib_latch = 0; | |
259 | } | |
260 | #ifdef DEBUG | |
261 | if (dopriodma) | |
262 | flags |= DMAGO_PRI; | |
263 | #endif | |
264 | if (hs->sc_flags & HPIBF_READ) { | |
265 | fhpibcmd[unit] = CT_REN | CT_8BIT; | |
266 | hs->sc_curcnt = count; | |
267 | dmago(hs->sc_dq.dq_ctlr, addr, count, flags|DMAGO_READ); | |
268 | if (fhpibrecv(unit, slave, sec, 0, 0) < 0) { | |
269 | #ifdef DEBUG | |
270 | printf("fhpibgo: recv failed, retrying...\n"); | |
271 | #endif | |
272 | (void) fhpibrecv(unit, slave, sec, 0, 0); | |
273 | } | |
274 | i = hd->hpib_cmd; | |
275 | hd->hpib_cmd = fhpibcmd[unit]; | |
276 | hd->hpib_ie = IDS_DMA(hs->sc_dq.dq_ctlr) | | |
277 | ((flags & DMAGO_WORD) ? IDS_WDMA : 0); | |
278 | return; | |
279 | } | |
280 | fhpibcmd[unit] = CT_REN | CT_8BIT | CT_FIFOSEL; | |
da1e0abb | 281 | if (count < hpibdmathresh) { |
60f56dfc KM |
282 | #ifdef DEBUG |
283 | fhpibnondma[unit]++; | |
da1e0abb KM |
284 | if (flags & DMAGO_WORD) |
285 | fhpibworddma[unit]--; | |
60f56dfc KM |
286 | #endif |
287 | hs->sc_curcnt = count; | |
288 | (void) fhpibsend(unit, slave, sec, addr, count); | |
289 | fhpibdone(unit); | |
290 | return; | |
291 | } | |
292 | count -= (flags & DMAGO_WORD) ? 2 : 1; | |
293 | hs->sc_curcnt = count; | |
294 | dmago(hs->sc_dq.dq_ctlr, addr, count, flags); | |
295 | if (fhpibsend(unit, slave, sec, 0, 0) < 0) { | |
296 | #ifdef DEBUG | |
297 | printf("fhpibgo: send failed, retrying...\n"); | |
298 | #endif | |
299 | (void) fhpibsend(unit, slave, sec, 0, 0); | |
300 | } | |
301 | i = hd->hpib_cmd; | |
302 | hd->hpib_cmd = fhpibcmd[unit]; | |
303 | hd->hpib_ie = IDS_DMA(hs->sc_dq.dq_ctlr) | IDS_WRITE | | |
304 | ((flags & DMAGO_WORD) ? IDS_WDMA : 0); | |
305 | } | |
306 | ||
307 | fhpibdone(unit) | |
308 | { | |
309 | register struct hpib_softc *hs = &hpib_softc[unit]; | |
310 | register struct fhpibdevice *hd; | |
311 | register char *addr; | |
312 | register int cnt; | |
313 | ||
314 | hd = (struct fhpibdevice *)hs->sc_hc->hp_addr; | |
315 | cnt = hs->sc_curcnt; | |
316 | hs->sc_addr += cnt; | |
317 | hs->sc_count -= cnt; | |
318 | #ifdef DEBUG | |
319 | if ((fhpibdebug & FDB_DMA) && fhpibdebugunit == unit) | |
320 | printf("fhpibdone: addr %x cnt %d\n", | |
321 | hs->sc_addr, hs->sc_count); | |
322 | #endif | |
323 | if (hs->sc_flags & HPIBF_READ) | |
324 | hd->hpib_imask = IM_IDLE | IM_BYTE; | |
325 | else { | |
326 | cnt = hs->sc_count; | |
327 | if (cnt) { | |
328 | addr = hs->sc_addr; | |
329 | hd->hpib_imask = IM_IDLE | IM_ROOM; | |
60f56dfc | 330 | FHPIBWAIT(hd, IM_IDLE); |
60f56dfc KM |
331 | hd->hpib_stat = ST_WRITE; |
332 | while (--cnt) { | |
333 | hd->hpib_data = *addr++; | |
334 | FHPIBWAIT(hd, IM_ROOM); | |
335 | } | |
336 | hd->hpib_stat = ST_EOI; | |
337 | hd->hpib_data = *addr; | |
338 | } | |
339 | hd->hpib_imask = IM_IDLE; | |
340 | } | |
341 | hs->sc_flags |= HPIBF_DONE; | |
342 | hd->hpib_stat = ST_IENAB; | |
343 | hd->hpib_ie = IDS_IE; | |
344 | } | |
345 | ||
346 | fhpibintr(unit) | |
347 | register int unit; | |
348 | { | |
349 | register struct hpib_softc *hs = &hpib_softc[unit]; | |
350 | register struct fhpibdevice *hd; | |
351 | register struct devqueue *dq; | |
352 | register int stat0; | |
353 | ||
354 | hd = (struct fhpibdevice *)hs->sc_hc->hp_addr; | |
355 | stat0 = hd->hpib_ids; | |
356 | if ((stat0 & (IDS_IE|IDS_IR)) != (IDS_IE|IDS_IR)) { | |
357 | #ifdef DEBUG | |
358 | if ((fhpibdebug & FDB_FAIL) && (stat0 & IDS_IR) && | |
359 | (hs->sc_flags & (HPIBF_IO|HPIBF_DONE)) != HPIBF_IO) | |
360 | printf("hpib%d: fhpibintr: bad status %x\n", | |
361 | unit, stat0); | |
362 | fhpibbadint[0]++; | |
363 | #endif | |
364 | return(0); | |
365 | } | |
366 | if ((hs->sc_flags & (HPIBF_IO|HPIBF_DONE)) == HPIBF_IO) { | |
367 | #ifdef DEBUG | |
368 | fhpibbadint[1]++; | |
369 | #endif | |
370 | return(0); | |
371 | } | |
372 | #ifdef DEBUG | |
373 | if ((fhpibdebug & FDB_DMA) && fhpibdebugunit == unit) | |
374 | printf("fhpibintr: flags %x\n", hs->sc_flags); | |
375 | #endif | |
376 | dq = hs->sc_sq.dq_forw; | |
377 | if (hs->sc_flags & HPIBF_IO) { | |
378 | stat0 = hd->hpib_cmd; | |
379 | hd->hpib_cmd = fhpibcmd[unit] & ~CT_8BIT; | |
380 | hd->hpib_stat = 0; | |
381 | hd->hpib_cmd = CT_REN | CT_8BIT; | |
382 | stat0 = hd->hpib_intr; | |
383 | hd->hpib_imask = 0; | |
384 | hs->sc_flags &= ~(HPIBF_DONE|HPIBF_IO|HPIBF_READ); | |
385 | dmafree(&hs->sc_dq); | |
386 | (dq->dq_driver->d_intr)(dq->dq_unit); | |
387 | } else if (hs->sc_flags & HPIBF_PPOLL) { | |
388 | stat0 = hd->hpib_intr; | |
389 | #ifdef DEBUG | |
390 | if ((fhpibdebug & FDB_FAIL) && | |
391 | doppollint && (stat0 & IM_PPRESP) == 0) | |
392 | printf("hpib%d: fhpibintr: bad intr reg %x\n", | |
393 | unit, stat0); | |
394 | #endif | |
395 | hd->hpib_stat = 0; | |
396 | hd->hpib_imask = 0; | |
397 | #ifdef DEBUG | |
398 | stat0 = fhpibppoll(unit); | |
399 | if ((fhpibdebug & FDB_PPOLL) && unit == fhpibdebugunit) | |
400 | printf("fhpibintr: got PPOLL status %x\n", stat0); | |
401 | if ((stat0 & (0x80 >> dq->dq_slave)) == 0) { | |
9acfa6cd MH |
402 | /* |
403 | * XXX give it another shot (68040) | |
404 | */ | |
405 | fhpibppollfail[unit]++; | |
406 | DELAY(fhpibppolldelay); | |
407 | stat0 = fhpibppoll(unit); | |
408 | if ((stat0 & (0x80 >> dq->dq_slave)) == 0 && | |
409 | (fhpibdebug & FDB_PPOLL) && unit == fhpibdebugunit) | |
410 | printf("fhpibintr: PPOLL: unit %d slave %d stat %x\n", | |
411 | unit, dq->dq_slave, stat0); | |
60f56dfc KM |
412 | } |
413 | #endif | |
414 | hs->sc_flags &= ~HPIBF_PPOLL; | |
415 | (dq->dq_driver->d_intr)(dq->dq_unit); | |
416 | } | |
417 | return(1); | |
418 | } | |
419 | ||
420 | fhpibppoll(unit) | |
421 | { | |
422 | register struct fhpibdevice *hd; | |
423 | register int ppoll; | |
424 | ||
425 | hd = (struct fhpibdevice *)hpib_softc[unit].sc_hc->hp_addr; | |
426 | hd->hpib_stat = 0; | |
427 | hd->hpib_psense = 0; | |
428 | hd->hpib_pmask = 0xFF; | |
429 | hd->hpib_imask = IM_PPRESP | IM_PABORT; | |
430 | DELAY(25); | |
431 | hd->hpib_intr = IM_PABORT; | |
432 | ppoll = hd->hpib_data; | |
433 | if (hd->hpib_intr & IM_PABORT) | |
434 | ppoll = 0; | |
435 | hd->hpib_imask = 0; | |
436 | hd->hpib_pmask = 0; | |
437 | hd->hpib_stat = ST_IENAB; | |
438 | return(ppoll); | |
439 | } | |
440 | ||
441 | fhpibwait(hd, x) | |
442 | register struct fhpibdevice *hd; | |
443 | { | |
444 | register int timo = hpibtimeout; | |
445 | ||
446 | while ((hd->hpib_intr & x) == 0 && --timo) | |
da1e0abb | 447 | DELAY(1); |
60f56dfc KM |
448 | if (timo == 0) { |
449 | #ifdef DEBUG | |
450 | if (fhpibdebug & FDB_FAIL) | |
451 | printf("fhpibwait(%x, %x) timeout\n", hd, x); | |
452 | #endif | |
453 | return(-1); | |
454 | } | |
455 | return(0); | |
456 | } | |
457 | ||
458 | /* | |
88a0c57a | 459 | * XXX: this will have to change if we ever allow more than one |
60f56dfc KM |
460 | * pending operation per HP-IB. |
461 | */ | |
88a0c57a CT |
462 | void |
463 | fhpibppwatch(arg) | |
464 | void *arg; | |
60f56dfc | 465 | { |
88a0c57a CT |
466 | register int unit; |
467 | register struct hpib_softc *hs; | |
60f56dfc KM |
468 | register struct fhpibdevice *hd; |
469 | register int slave; | |
470 | ||
88a0c57a CT |
471 | unit = (int)arg; |
472 | hs = &hpib_softc[unit]; | |
60f56dfc KM |
473 | if ((hs->sc_flags & HPIBF_PPOLL) == 0) |
474 | return; | |
475 | hd = (struct fhpibdevice *)hs->sc_hc->hp_addr; | |
476 | slave = (0x80 >> hs->sc_sq.dq_forw->dq_slave); | |
477 | #ifdef DEBUG | |
478 | if (!doppollint) { | |
479 | if (fhpibppoll(unit) & slave) { | |
480 | hd->hpib_stat = ST_IENAB; | |
481 | hd->hpib_imask = IM_IDLE | IM_ROOM; | |
482 | } else | |
88a0c57a | 483 | timeout(fhpibppwatch, (void *)unit, 1); |
60f56dfc KM |
484 | return; |
485 | } | |
486 | if ((fhpibdebug & FDB_PPOLL) && unit == fhpibdebugunit) | |
487 | printf("fhpibppwatch: sense request on %d\n", unit); | |
488 | #endif | |
489 | hd->hpib_psense = ~slave; | |
490 | hd->hpib_pmask = slave; | |
491 | hd->hpib_stat = ST_IENAB; | |
492 | hd->hpib_imask = IM_PPRESP | IM_PABORT; | |
493 | hd->hpib_ie = IDS_IE; | |
494 | } | |
495 | #endif |