ppi.c revision 1.11 1 /* $NetBSD: ppi.c,v 1.11 1997/01/30 09:14:16 thorpej 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 * @(#)ppi.c 8.1 (Berkeley) 6/16/93
37 */
38
39 /*
40 * Printer/Plotter HPIB interface
41 */
42
43 #include <sys/param.h>
44 #include <sys/systm.h>
45 #include <sys/errno.h>
46 #include <sys/uio.h>
47 #include <sys/malloc.h>
48 #include <sys/device.h>
49 #include <sys/conf.h>
50
51 #include <hp300/dev/hpibvar.h>
52
53 #include <hp300/dev/ppiioctl.h>
54
55 struct ppi_softc {
56 struct device sc_dev;
57 int sc_flags;
58 struct hpibqueue sc_hq; /* HP-IB job queue entry */
59 struct ppiparam sc_param;
60 #define sc_burst sc_param.burst
61 #define sc_timo sc_param.timo
62 #define sc_delay sc_param.delay
63 int sc_sec;
64 int sc_slave; /* HP-IB slave address */
65 };
66
67 /* sc_flags values */
68 #define PPIF_ALIVE 0x01
69 #define PPIF_OPEN 0x02
70 #define PPIF_UIO 0x04
71 #define PPIF_TIMO 0x08
72 #define PPIF_DELAY 0x10
73
74 int ppimatch __P((struct device *, struct cfdata *, void *));
75 void ppiattach __P((struct device *, struct device *, void *));
76
77 struct cfattach ppi_ca = {
78 sizeof(struct ppi_softc), ppimatch, ppiattach
79 };
80
81 struct cfdriver ppi_cd = {
82 NULL, "ppi", DV_DULL
83 };
84
85 void ppistart __P((void *));
86 void ppinoop __P((void *));
87
88 void ppitimo __P((void *));
89 int ppirw __P((dev_t, struct uio *));
90 int ppihztoms __P((int));
91 int ppimstohz __P((int));
92
93 bdev_decl(ppi);
94 cdev_decl(ppi);
95
96 #define UNIT(x) minor(x)
97
98 #ifdef DEBUG
99 int ppidebug = 0x80;
100 #define PDB_FOLLOW 0x01
101 #define PDB_IO 0x02
102 #define PDB_NOCHECK 0x80
103 #endif
104
105 int
106 ppimatch(parent, match, aux)
107 struct device *parent;
108 struct cfdata *match;
109 void *aux;
110 {
111 struct hpibbus_attach_args *ha = aux;
112
113 /*
114 * The printer/plotter doesn't return an ID tag.
115 * The check below prevents us from matching a CS80
116 * device by mistake.
117 */
118 if (ha->ha_id & 0x200)
119 return (0);
120
121 /*
122 * To prevent matching all unused slots on the bus, we
123 * don't allow wildcarded locators.
124 */
125 if (match->hpibbuscf_slave == HPIBBUS_SLAVE_UNK ||
126 match->hpibbuscf_punit == HPIBBUS_PUNIT_UNK)
127 return (0);
128
129 return (1);
130 }
131
132 void
133 ppiattach(parent, self, aux)
134 struct device *parent, *self;
135 void *aux;
136 {
137 struct ppi_softc *sc = (struct ppi_softc *)self;
138 struct hpibbus_attach_args *ha = aux;
139
140 printf("\n");
141
142 sc->sc_slave = ha->ha_slave;
143
144 /* Initialize the hpib queue entry. */
145 sc->sc_hq.hq_softc = sc;
146 sc->sc_hq.hq_slave = sc->sc_slave;
147 sc->sc_hq.hq_start = ppistart;
148 sc->sc_hq.hq_go = ppinoop;
149 sc->sc_hq.hq_intr = ppinoop;
150
151 sc->sc_flags = PPIF_ALIVE;
152 }
153
154 void
155 ppinoop(arg)
156 void *arg;
157 {
158 /* Noop! */
159 }
160
161 int
162 ppiopen(dev, flags, fmt, p)
163 dev_t dev;
164 int flags, fmt;
165 struct proc *p;
166 {
167 register int unit = UNIT(dev);
168 struct ppi_softc *sc;
169
170 if (unit >= ppi_cd.cd_ndevs ||
171 (sc = ppi_cd.cd_devs[unit]) == NULL ||
172 (sc->sc_flags & PPIF_ALIVE) == 0)
173 return (ENXIO);
174
175 #ifdef DEBUG
176 if (ppidebug & PDB_FOLLOW)
177 printf("ppiopen(%x, %x): flags %x\n",
178 dev, flags, sc->sc_flags);
179 #endif
180 if (sc->sc_flags & PPIF_OPEN)
181 return (EBUSY);
182 sc->sc_flags |= PPIF_OPEN;
183 sc->sc_burst = PPI_BURST;
184 sc->sc_timo = ppimstohz(PPI_TIMO);
185 sc->sc_delay = ppimstohz(PPI_DELAY);
186 sc->sc_sec = -1;
187 return(0);
188 }
189
190 int
191 ppiclose(dev, flags, fmt, p)
192 dev_t dev;
193 int flags, fmt;
194 struct proc *p;
195 {
196 register int unit = UNIT(dev);
197 struct ppi_softc *sc = ppi_cd.cd_devs[unit];
198
199 #ifdef DEBUG
200 if (ppidebug & PDB_FOLLOW)
201 printf("ppiclose(%x, %x): flags %x\n",
202 dev, flags, sc->sc_flags);
203 #endif
204 sc->sc_flags &= ~PPIF_OPEN;
205 return(0);
206 }
207
208 void
209 ppistart(arg)
210 void *arg;
211 {
212 struct ppi_softc *sc = arg;
213
214 #ifdef DEBUG
215 if (ppidebug & PDB_FOLLOW)
216 printf("ppistart(%x)\n", unit);
217 #endif
218 sc->sc_flags &= ~PPIF_DELAY;
219 wakeup(sc);
220 }
221
222 void
223 ppitimo(arg)
224 void *arg;
225 {
226 struct ppi_softc *sc = arg;
227
228 #ifdef DEBUG
229 if (ppidebug & PDB_FOLLOW)
230 printf("ppitimo(%x)\n", sc->sc_dev.dv_unit);
231 #endif
232 sc->sc_flags &= ~(PPIF_UIO|PPIF_TIMO);
233 wakeup(sc);
234 }
235
236 int
237 ppiread(dev, uio, flags)
238 dev_t dev;
239 struct uio *uio;
240 int flags;
241 {
242
243 #ifdef DEBUG
244 if (ppidebug & PDB_FOLLOW)
245 printf("ppiread(%x, %x)\n", dev, uio);
246 #endif
247 return (ppirw(dev, uio));
248 }
249
250 int
251 ppiwrite(dev, uio, flags)
252 dev_t dev;
253 struct uio *uio;
254 int flags;
255 {
256
257 #ifdef DEBUG
258 if (ppidebug & PDB_FOLLOW)
259 printf("ppiwrite(%x, %x)\n", dev, uio);
260 #endif
261 return (ppirw(dev, uio));
262 }
263
264 int
265 ppirw(dev, uio)
266 dev_t dev;
267 register struct uio *uio;
268 {
269 int unit = UNIT(dev);
270 struct ppi_softc *sc = ppi_cd.cd_devs[unit];
271 register int s, len, cnt;
272 register char *cp;
273 int error = 0, gotdata = 0;
274 int buflen, ctlr, slave;
275 char *buf;
276
277 if (uio->uio_resid == 0)
278 return(0);
279
280 ctlr = sc->sc_dev.dv_parent->dv_unit;
281 slave = sc->sc_slave;
282
283 #ifdef DEBUG
284 if (ppidebug & (PDB_FOLLOW|PDB_IO))
285 printf("ppirw(%x, %x, %c): burst %d, timo %d, resid %x\n",
286 dev, uio, uio->uio_rw == UIO_READ ? 'R' : 'W',
287 sc->sc_burst, sc->sc_timo, uio->uio_resid);
288 #endif
289 buflen = min(sc->sc_burst, uio->uio_resid);
290 buf = (char *)malloc(buflen, M_DEVBUF, M_WAITOK);
291 sc->sc_flags |= PPIF_UIO;
292 if (sc->sc_timo > 0) {
293 sc->sc_flags |= PPIF_TIMO;
294 timeout(ppitimo, sc, sc->sc_timo);
295 }
296 while (uio->uio_resid > 0) {
297 len = min(buflen, uio->uio_resid);
298 cp = buf;
299 if (uio->uio_rw == UIO_WRITE) {
300 error = uiomove(cp, len, uio);
301 if (error)
302 break;
303 }
304 again:
305 s = splbio();
306 if ((sc->sc_flags & PPIF_UIO) &&
307 hpibreq(sc->sc_dev.dv_parent, &sc->sc_hq) == 0)
308 sleep(sc, PRIBIO+1);
309 /*
310 * Check if we timed out during sleep or uiomove
311 */
312 (void) splsoftclock();
313 if ((sc->sc_flags & PPIF_UIO) == 0) {
314 #ifdef DEBUG
315 if (ppidebug & PDB_IO)
316 printf("ppirw: uiomove/sleep timo, flags %x\n",
317 sc->sc_flags);
318 #endif
319 if (sc->sc_flags & PPIF_TIMO) {
320 untimeout(ppitimo, sc);
321 sc->sc_flags &= ~PPIF_TIMO;
322 }
323 splx(s);
324 break;
325 }
326 splx(s);
327 /*
328 * Perform the operation
329 */
330 if (uio->uio_rw == UIO_WRITE)
331 cnt = hpibsend(ctlr, slave, sc->sc_sec, cp, len);
332 else
333 cnt = hpibrecv(ctlr, slave, sc->sc_sec, cp, len);
334 s = splbio();
335 hpibfree(sc->sc_dev.dv_parent, &sc->sc_hq);
336 #ifdef DEBUG
337 if (ppidebug & PDB_IO)
338 printf("ppirw: %s(%d, %d, %x, %x, %d) -> %d\n",
339 uio->uio_rw == UIO_READ ? "recv" : "send",
340 ctlr, slave, sc->sc_sec, cp, len, cnt);
341 #endif
342 splx(s);
343 if (uio->uio_rw == UIO_READ) {
344 if (cnt) {
345 error = uiomove(cp, cnt, uio);
346 if (error)
347 break;
348 gotdata++;
349 }
350 /*
351 * Didn't get anything this time, but did in the past.
352 * Consider us done.
353 */
354 else if (gotdata)
355 break;
356 }
357 s = splsoftclock();
358 /*
359 * Operation timeout (or non-blocking), quit now.
360 */
361 if ((sc->sc_flags & PPIF_UIO) == 0) {
362 #ifdef DEBUG
363 if (ppidebug & PDB_IO)
364 printf("ppirw: timeout/done\n");
365 #endif
366 splx(s);
367 break;
368 }
369 /*
370 * Implement inter-read delay
371 */
372 if (sc->sc_delay > 0) {
373 sc->sc_flags |= PPIF_DELAY;
374 timeout(ppistart, sc, sc->sc_delay);
375 error = tsleep(sc, PCATCH|PZERO+1, "hpib", 0);
376 if (error) {
377 splx(s);
378 break;
379 }
380 }
381 splx(s);
382 /*
383 * Must not call uiomove again til we've used all data
384 * that we already grabbed.
385 */
386 if (uio->uio_rw == UIO_WRITE && cnt != len) {
387 cp += cnt;
388 len -= cnt;
389 cnt = 0;
390 goto again;
391 }
392 }
393 s = splsoftclock();
394 if (sc->sc_flags & PPIF_TIMO) {
395 untimeout(ppitimo, sc);
396 sc->sc_flags &= ~PPIF_TIMO;
397 }
398 if (sc->sc_flags & PPIF_DELAY) {
399 untimeout(ppistart, sc);
400 sc->sc_flags &= ~PPIF_DELAY;
401 }
402 splx(s);
403 /*
404 * Adjust for those chars that we uiomove'ed but never wrote
405 */
406 if (uio->uio_rw == UIO_WRITE && cnt != len) {
407 uio->uio_resid += (len - cnt);
408 #ifdef DEBUG
409 if (ppidebug & PDB_IO)
410 printf("ppirw: short write, adjust by %d\n",
411 len-cnt);
412 #endif
413 }
414 free(buf, M_DEVBUF);
415 #ifdef DEBUG
416 if (ppidebug & (PDB_FOLLOW|PDB_IO))
417 printf("ppirw: return %d, resid %d\n", error, uio->uio_resid);
418 #endif
419 return (error);
420 }
421
422 int
423 ppiioctl(dev, cmd, data, flag, p)
424 dev_t dev;
425 u_long cmd;
426 caddr_t data;
427 int flag;
428 struct proc *p;
429 {
430 struct ppi_softc *sc = ppi_cd.cd_devs[UNIT(dev)];
431 struct ppiparam *pp, *upp;
432 int error = 0;
433
434 switch (cmd) {
435 case PPIIOCGPARAM:
436 pp = &sc->sc_param;
437 upp = (struct ppiparam *)data;
438 upp->burst = pp->burst;
439 upp->timo = ppihztoms(pp->timo);
440 upp->delay = ppihztoms(pp->delay);
441 break;
442 case PPIIOCSPARAM:
443 pp = &sc->sc_param;
444 upp = (struct ppiparam *)data;
445 if (upp->burst < PPI_BURST_MIN || upp->burst > PPI_BURST_MAX ||
446 upp->delay < PPI_DELAY_MIN || upp->delay > PPI_DELAY_MAX)
447 return(EINVAL);
448 pp->burst = upp->burst;
449 pp->timo = ppimstohz(upp->timo);
450 pp->delay = ppimstohz(upp->delay);
451 break;
452 case PPIIOCSSEC:
453 sc->sc_sec = *(int *)data;
454 break;
455 default:
456 return(EINVAL);
457 }
458 return (error);
459 }
460
461 int
462 ppihztoms(h)
463 int h;
464 {
465 extern int hz;
466 register int m = h;
467
468 if (m > 0)
469 m = m * 1000 / hz;
470 return(m);
471 }
472
473 int
474 ppimstohz(m)
475 int m;
476 {
477 extern int hz;
478 register int h = m;
479
480 if (h > 0) {
481 h = h * hz / 1000;
482 if (h == 0)
483 h = 1000 / hz;
484 }
485 return(h);
486 }
487