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