hpib.c revision 1.14 1 /* $NetBSD: hpib.c,v 1.14 1997/03/31 07:34:24 scottr Exp $ */
2
3 /*
4 * Copyright (c) 1996, 1997 Jason R. Thorpe. All rights reserved.
5 * Copyright (c) 1982, 1990, 1993
6 * The Regents of the University of California. All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. All advertising materials mentioning features or use of this software
17 * must display the following acknowledgement:
18 * This product includes software developed by the University of
19 * California, Berkeley and its contributors.
20 * 4. Neither the name of the University nor the names of its contributors
21 * may be used to endorse or promote products derived from this software
22 * without specific prior written permission.
23 *
24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34 * SUCH DAMAGE.
35 *
36 * @(#)hpib.c 8.2 (Berkeley) 1/12/94
37 */
38
39 /*
40 * HP-IB bus driver
41 */
42
43 #include <sys/param.h>
44 #include <sys/systm.h>
45 #include <sys/buf.h>
46 #include <sys/malloc.h>
47 #include <sys/device.h>
48
49 #include <hp300/dev/dmavar.h>
50
51 #include <hp300/dev/hpibvar.h>
52
53 #include <machine/cpu.h>
54 #include <hp300/hp300/isr.h>
55
56 int hpibbusmatch __P((struct device *, struct cfdata *, void *));
57 void hpibbusattach __P((struct device *, struct device *, void *));
58
59 struct cfattach hpibbus_ca = {
60 sizeof(struct hpibbus_softc), hpibbusmatch, hpibbusattach
61 };
62
63 struct cfdriver hpibbus_cd = {
64 NULL, "hpibbus", DV_DULL
65 };
66
67 void hpibbus_attach_children __P((struct hpibbus_softc *));
68 int hpibbussearch __P((struct device *, struct cfdata *, void *));
69 int hpibbusprint __P((void *, const char *));
70
71 int hpibbus_alloc __P((struct hpibbus_softc *, int, int));
72 void hpibbus_free __P((struct hpibbus_softc *, int, int));
73
74 void hpibstart __P((void *));
75 void hpibdone __P((void *));
76
77 int hpibtimeout = 100000; /* # of status tests before we give up */
78 int hpibidtimeout = 10000; /* # of status tests for hpibid() calls */
79 int hpibdmathresh = 3; /* byte count beyond which to attempt dma */
80
81 /*
82 * HP-IB is essentially an IEEE 488 bus, with an HP command
83 * set (CS/80 on `newer' devices, Amigo on before-you-were-born
84 * devices) thrown on top. Devices that respond to CS/80 (and
85 * probably Amigo, too) are tagged with a 16-bit ID.
86 *
87 * HP-IB has a 2-level addressing scheme; slave, the analog
88 * of a SCSI ID, and punit, the analog of a SCSI LUN. Unforunately,
89 * IDs are on a per-slave basis; punits are often used for disk
90 * drives that have an accompanying tape drive on the second punit.
91 *
92 * In addition, not all HP-IB devices speak CS/80 or Amigo.
93 * Examples of such devices are HP-IB plotters, which simply
94 * take raw plotter commands over 488. These devices do not
95 * have ID tags, and often the host cannot even tell if such
96 * a device is attached to the system!
97 *
98 * These two nasty bits mean that we have to treat HP-IB as
99 * an indirect bus. However, since we are given some ID
100 * information, it is unreasonable to disallow cloning of
101 * CS/80 devices.
102 *
103 * To deal with all of this, we use the semi-twisted scheme
104 * in hpibbus_attach_children(). For each HP-IB slave, we loop
105 * through all of the possibly-configured children, allowing
106 * them to modify the punit parameter (but NOT the slave!).
107 *
108 * This is evil, but what can you do?
109 */
110
111 int
112 hpibbusmatch(parent, match, aux)
113 struct device *parent;
114 struct cfdata *match;
115 void *aux;
116 {
117
118 return (1);
119 }
120
121 void
122 hpibbusattach(parent, self, aux)
123 struct device *parent, *self;
124 void *aux;
125 {
126 struct hpibbus_softc *sc = (struct hpibbus_softc *)self;
127 struct hpibdev_attach_args *ha = aux;
128
129 printf("\n");
130
131 /* Get the operations vector for the controller. */
132 sc->sc_ops = ha->ha_ops;
133 sc->sc_type = ha->ha_type; /* XXX */
134 sc->sc_ba = ha->ha_ba;
135 *(ha->ha_softcpp) = sc; /* XXX */
136
137 hpibreset(self->dv_unit); /* XXX souldn't be here */
138
139 /*
140 * Initialize the DMA queue entry.
141 */
142 sc->sc_dq = (struct dmaqueue *)malloc(sizeof(struct dmaqueue),
143 M_DEVBUF, M_NOWAIT);
144 if (sc->sc_dq == NULL) {
145 printf("%s: can't allocate DMA queue entry\n", self->dv_xname);
146 return;
147 }
148 sc->sc_dq->dq_softc = sc;
149 sc->sc_dq->dq_start = hpibstart;
150 sc->sc_dq->dq_done = hpibdone;
151
152 /* Initialize the slave request queue. */
153 TAILQ_INIT(&sc->sc_queue);
154
155 /* Attach any devices on the bus. */
156 hpibbus_attach_children(sc);
157 }
158
159 void
160 hpibbus_attach_children(sc)
161 struct hpibbus_softc *sc;
162 {
163 struct hpibbus_attach_args ha;
164 int slave;
165
166 for (slave = 0; slave < 8; slave++) {
167 /*
168 * Get the ID tag for the device, if any.
169 * Plotters won't identify themselves, and
170 * get the same value as non-existent devices.
171 */
172 ha.ha_id = hpibid(sc->sc_dev.dv_unit, slave);
173
174 ha.ha_slave = slave; /* not to be modified by children */
175 ha.ha_punit = 0; /* children modify this */
176
177 /*
178 * Search though all configured children for this bus.
179 */
180 (void)config_search(hpibbussearch, &sc->sc_dev, &ha);
181 }
182 }
183
184 int
185 hpibbussearch(parent, cf, aux)
186 struct device *parent;
187 struct cfdata *cf;
188 void *aux;
189 {
190 struct hpibbus_softc *sc = (struct hpibbus_softc *)parent;
191 struct hpibbus_attach_args *ha = aux;
192
193 /* Make sure this is in a consistent state. */
194 ha->ha_punit = 0;
195
196 if ((*cf->cf_attach->ca_match)(parent, cf, ha) > 0) {
197 /*
198 * The device probe has succeeded, and filled in
199 * the punit information. Make sure the configuration
200 * allows for this slave/punit combination.
201 */
202 if (cf->hpibbuscf_slave != HPIBBUS_SLAVE_UNK &&
203 cf->hpibbuscf_slave != ha->ha_slave)
204 goto out;
205 if (cf->hpibbuscf_punit != HPIBBUS_PUNIT_UNK &&
206 cf->hpibbuscf_punit != ha->ha_punit)
207 goto out;
208
209 /*
210 * Allocate the device's address from the bus's
211 * resource map.
212 */
213 if (hpibbus_alloc(sc, ha->ha_slave, ha->ha_punit))
214 goto out;
215
216 /*
217 * This device is allowed; attach it.
218 */
219 config_attach(parent, cf, ha, hpibbusprint);
220 }
221 out:
222 return (0);
223 }
224
225 int
226 hpibbusprint(aux, pnp)
227 void *aux;
228 const char *pnp;
229 {
230 struct hpibbus_attach_args *ha = aux;
231
232 printf(" slave %d punit %d", ha->ha_slave, ha->ha_punit);
233 return (UNCONF);
234 }
235
236 int
237 hpibdevprint(aux, pnp)
238 void *aux;
239 const char *pnp;
240 {
241
242 /* only hpibbus's can attach to hpibdev's -- easy. */
243 if (pnp != NULL)
244 printf("hpibbus at %s", pnp);
245 return (UNCONF);
246 }
247
248 void
249 hpibreset(unit)
250 int unit;
251 {
252 struct hpibbus_softc *sc = hpibbus_cd.cd_devs[unit];
253
254 (*sc->sc_ops->hpib_reset)(sc);
255 }
256
257 int
258 hpibreq(pdev, hq)
259 struct device *pdev;
260 struct hpibqueue *hq;
261 {
262 struct hpibbus_softc *sc = (struct hpibbus_softc *)pdev;
263 int s;
264
265 s = splhigh(); /* XXXthorpej */
266 TAILQ_INSERT_TAIL(&sc->sc_queue, hq, hq_list);
267 splx(s);
268
269 if (sc->sc_queue.tqh_first == hq)
270 return (1);
271
272 return (0);
273 }
274
275 void
276 hpibfree(pdev, hq)
277 struct device *pdev;
278 struct hpibqueue *hq;
279 {
280 struct hpibbus_softc *sc = (struct hpibbus_softc *)pdev;
281 int s;
282
283 s = splhigh(); /* XXXthorpej */
284 TAILQ_REMOVE(&sc->sc_queue, hq, hq_list);
285 splx(s);
286
287 if ((hq = sc->sc_queue.tqh_first) != NULL)
288 (*hq->hq_start)(hq->hq_softc);
289 }
290
291 int
292 hpibid(unit, slave)
293 int unit, slave;
294 {
295 short id;
296 int ohpibtimeout;
297
298 /*
299 * XXX shorten timeout value so autoconfig doesn't
300 * take forever on slow CPUs.
301 */
302 ohpibtimeout = hpibtimeout;
303 hpibtimeout = hpibidtimeout * (cpuspeed / 8);
304 if (hpibrecv(unit, 31, slave, &id, 2) != 2)
305 id = 0;
306 hpibtimeout = ohpibtimeout;
307 return(id);
308 }
309
310 int
311 hpibsend(unit, slave, sec, addr, cnt)
312 int unit, slave, sec, cnt;
313 void *addr;
314 {
315 struct hpibbus_softc *sc = hpibbus_cd.cd_devs[unit];
316
317 return ((*sc->sc_ops->hpib_send)(sc, slave, sec, addr, cnt));
318 }
319
320 int
321 hpibrecv(unit, slave, sec, addr, cnt)
322 int unit, slave, sec, cnt;
323 void *addr;
324 {
325 struct hpibbus_softc *sc = hpibbus_cd.cd_devs[unit];
326
327 return ((*sc->sc_ops->hpib_recv)(sc, slave, sec, addr, cnt));
328 }
329
330 int
331 hpibpptest(unit, slave)
332 int unit;
333 int slave;
334 {
335 struct hpibbus_softc *sc = hpibbus_cd.cd_devs[unit];
336
337 return ((*sc->sc_ops->hpib_ppoll)(sc) & (0x80 >> slave));
338 }
339
340 void
341 hpibppclear(unit)
342 int unit;
343 {
344 struct hpibbus_softc *sc = hpibbus_cd.cd_devs[unit];
345
346 sc->sc_flags &= ~HPIBF_PPOLL;
347 }
348
349 void
350 hpibawait(unit)
351 int unit;
352 {
353 struct hpibbus_softc *sc = hpibbus_cd.cd_devs[unit];
354
355 sc->sc_flags |= HPIBF_PPOLL;
356 (*sc->sc_ops->hpib_ppwatch)(sc);
357 }
358
359 int
360 hpibswait(unit, slave)
361 int unit;
362 int slave;
363 {
364 struct hpibbus_softc *sc = hpibbus_cd.cd_devs[unit];
365 int timo = hpibtimeout;
366 int mask, (*ppoll) __P((struct hpibbus_softc *));
367
368 ppoll = sc->sc_ops->hpib_ppoll;
369 mask = 0x80 >> slave;
370 while (((*ppoll)(sc) & mask) == 0) {
371 if (--timo == 0) {
372 printf("%s: swait timeout\n", sc->sc_dev.dv_xname);
373 return(-1);
374 }
375 }
376 return(0);
377 }
378
379 int
380 hpibustart(unit)
381 int unit;
382 {
383 struct hpibbus_softc *sc = hpibbus_cd.cd_devs[unit];
384
385 if (sc->sc_type == HPIBA)
386 sc->sc_dq->dq_chan = DMA0;
387 else
388 sc->sc_dq->dq_chan = DMA0 | DMA1;
389 if (dmareq(sc->sc_dq))
390 return(1);
391 return(0);
392 }
393
394 void
395 hpibstart(arg)
396 void *arg;
397 {
398 struct hpibbus_softc *sc = arg;
399 struct hpibqueue *hq;
400
401 hq = sc->sc_queue.tqh_first;
402 (*hq->hq_go)(hq->hq_softc);
403 }
404
405 void
406 hpibgo(unit, slave, sec, vbuf, count, rw, timo)
407 int unit, slave, sec;
408 void *vbuf;
409 int count, rw, timo;
410 {
411 struct hpibbus_softc *sc = hpibbus_cd.cd_devs[unit];
412
413 (*sc->sc_ops->hpib_go)(sc, slave, sec, vbuf, count, rw, timo);
414 }
415
416 void
417 hpibdone(arg)
418 void *arg;
419 {
420 struct hpibbus_softc *sc = arg;
421
422 (*sc->sc_ops->hpib_done)(sc);
423 }
424
425 int
426 hpibintr(arg)
427 void *arg;
428 {
429 struct hpibbus_softc *sc = arg;
430
431 return ((sc->sc_ops->hpib_intr)(arg));
432 }
433
434 int
435 hpibbus_alloc(sc, slave, punit)
436 struct hpibbus_softc *sc;
437 int slave, punit;
438 {
439
440 if (slave >= HPIB_NSLAVES ||
441 punit >= HPIB_NPUNITS)
442 panic("hpibbus_alloc: device address out of range");
443
444 if (sc->sc_rmap[slave][punit] == 0) {
445 sc->sc_rmap[slave][punit] = 1;
446 return (0);
447 }
448 return (1);
449 }
450
451 void
452 hpibbus_free(sc, slave, punit)
453 struct hpibbus_softc *sc;
454 int slave, punit;
455 {
456
457 if (slave >= HPIB_NSLAVES ||
458 punit >= HPIB_NPUNITS)
459 panic("hpibbus_free: device address out of range");
460
461 #ifdef DIAGNOSTIC
462 if (sc->sc_rmap[slave][punit] == 0)
463 panic("hpibbus_free: not allocated");
464 #endif
465
466 sc->sc_rmap[slave][punit] = 0;
467 }
468