ppi.c revision 1.27 1 /* $NetBSD: ppi.c,v 1.27 2003/08/07 16:27:34 agc Exp $ */
2
3 /*-
4 * Copyright (c) 1996, 1997 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Jason R. Thorpe.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * 3. All advertising materials mentioning features or use of this software
19 * must display the following acknowledgement:
20 * This product includes software developed by the NetBSD
21 * Foundation, Inc. and its contributors.
22 * 4. Neither the name of The NetBSD Foundation nor the names of its
23 * contributors may be used to endorse or promote products derived
24 * from this software without specific prior written permission.
25 *
26 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
27 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
28 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
30 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36 * POSSIBILITY OF SUCH DAMAGE.
37 */
38
39 /*
40 * Copyright (c) 1982, 1990, 1993
41 * The Regents of the University of California. All rights reserved.
42 *
43 * Redistribution and use in source and binary forms, with or without
44 * modification, are permitted provided that the following conditions
45 * are met:
46 * 1. Redistributions of source code must retain the above copyright
47 * notice, this list of conditions and the following disclaimer.
48 * 2. Redistributions in binary form must reproduce the above copyright
49 * notice, this list of conditions and the following disclaimer in the
50 * documentation and/or other materials provided with the distribution.
51 * 3. Neither the name of the University nor the names of its contributors
52 * may be used to endorse or promote products derived from this software
53 * without specific prior written permission.
54 *
55 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
56 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
57 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
58 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
59 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
60 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
61 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
62 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
63 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
64 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
65 * SUCH DAMAGE.
66 *
67 * @(#)ppi.c 8.1 (Berkeley) 6/16/93
68 */
69
70 /*
71 * Printer/Plotter HPIB interface
72 */
73
74 #include <sys/cdefs.h>
75 __KERNEL_RCSID(0, "$NetBSD: ppi.c,v 1.27 2003/08/07 16:27:34 agc Exp $");
76
77 #include <sys/param.h>
78 #include <sys/systm.h>
79 #include <sys/callout.h>
80 #include <sys/conf.h>
81 #include <sys/device.h>
82 #include <sys/errno.h>
83 #include <sys/malloc.h>
84 #include <sys/proc.h>
85 #include <sys/uio.h>
86
87 #include <hp300/dev/hpibvar.h>
88
89 #include <hp300/dev/ppiioctl.h>
90
91 struct ppi_softc {
92 struct device sc_dev;
93 int sc_flags;
94 struct hpibqueue sc_hq; /* HP-IB job queue entry */
95 struct ppiparam sc_param;
96 #define sc_burst sc_param.burst
97 #define sc_timo sc_param.timo
98 #define sc_delay sc_param.delay
99 int sc_sec;
100 int sc_slave; /* HP-IB slave address */
101 struct callout sc_timo_ch;
102 struct callout sc_start_ch;
103 };
104
105 /* sc_flags values */
106 #define PPIF_ALIVE 0x01
107 #define PPIF_OPEN 0x02
108 #define PPIF_UIO 0x04
109 #define PPIF_TIMO 0x08
110 #define PPIF_DELAY 0x10
111
112 int ppimatch __P((struct device *, struct cfdata *, void *));
113 void ppiattach __P((struct device *, struct device *, void *));
114
115 CFATTACH_DECL(ppi, sizeof(struct ppi_softc),
116 ppimatch, ppiattach, NULL, NULL);
117
118 extern struct cfdriver ppi_cd;
119
120 dev_type_open(ppiopen);
121 dev_type_close(ppiclose);
122 dev_type_read(ppiread);
123 dev_type_write(ppiwrite);
124 dev_type_ioctl(ppiioctl);
125
126 const struct cdevsw ppi_cdevsw = {
127 ppiopen, ppiclose, ppiread, ppiwrite, ppiioctl,
128 nostop, notty, nopoll, nommap, nokqfilter,
129 };
130
131 void ppistart __P((void *));
132 void ppinoop __P((void *));
133
134 void ppitimo __P((void *));
135 int ppirw __P((dev_t, struct uio *));
136 int ppihztoms __P((int));
137 int ppimstohz __P((int));
138
139 #define UNIT(x) minor(x)
140
141 #ifdef DEBUG
142 int ppidebug = 0x80;
143 #define PDB_FOLLOW 0x01
144 #define PDB_IO 0x02
145 #define PDB_NOCHECK 0x80
146 #endif
147
148 int
149 ppimatch(parent, match, aux)
150 struct device *parent;
151 struct cfdata *match;
152 void *aux;
153 {
154 struct hpibbus_attach_args *ha = aux;
155
156 /*
157 * The printer/plotter doesn't return an ID tag.
158 * The check below prevents us from matching a CS80
159 * device by mistake.
160 */
161 if (ha->ha_id & 0x200)
162 return (0);
163
164 /*
165 * To prevent matching all unused slots on the bus, we
166 * don't allow wildcarded locators.
167 */
168 if (match->hpibbuscf_slave == HPIBBUSCF_SLAVE_DEFAULT ||
169 match->hpibbuscf_punit == HPIBBUSCF_PUNIT_DEFAULT)
170 return (0);
171
172 return (1);
173 }
174
175 void
176 ppiattach(parent, self, aux)
177 struct device *parent, *self;
178 void *aux;
179 {
180 struct ppi_softc *sc = (struct ppi_softc *)self;
181 struct hpibbus_attach_args *ha = aux;
182
183 printf("\n");
184
185 sc->sc_slave = ha->ha_slave;
186
187 callout_init(&sc->sc_timo_ch);
188 callout_init(&sc->sc_start_ch);
189
190 /* Initialize the hpib queue entry. */
191 sc->sc_hq.hq_softc = sc;
192 sc->sc_hq.hq_slave = sc->sc_slave;
193 sc->sc_hq.hq_start = ppistart;
194 sc->sc_hq.hq_go = ppinoop;
195 sc->sc_hq.hq_intr = ppinoop;
196
197 sc->sc_flags = PPIF_ALIVE;
198 }
199
200 void
201 ppinoop(arg)
202 void *arg;
203 {
204 /* Noop! */
205 }
206
207 int
208 ppiopen(dev, flags, fmt, p)
209 dev_t dev;
210 int flags, fmt;
211 struct proc *p;
212 {
213 int unit = UNIT(dev);
214 struct ppi_softc *sc;
215
216 if (unit >= ppi_cd.cd_ndevs ||
217 (sc = ppi_cd.cd_devs[unit]) == NULL ||
218 (sc->sc_flags & PPIF_ALIVE) == 0)
219 return (ENXIO);
220
221 #ifdef DEBUG
222 if (ppidebug & PDB_FOLLOW)
223 printf("ppiopen(%x, %x): flags %x\n",
224 dev, flags, sc->sc_flags);
225 #endif
226 if (sc->sc_flags & PPIF_OPEN)
227 return (EBUSY);
228 sc->sc_flags |= PPIF_OPEN;
229 sc->sc_burst = PPI_BURST;
230 sc->sc_timo = ppimstohz(PPI_TIMO);
231 sc->sc_delay = ppimstohz(PPI_DELAY);
232 sc->sc_sec = -1;
233 return(0);
234 }
235
236 int
237 ppiclose(dev, flags, fmt, p)
238 dev_t dev;
239 int flags, fmt;
240 struct proc *p;
241 {
242 int unit = UNIT(dev);
243 struct ppi_softc *sc = ppi_cd.cd_devs[unit];
244
245 #ifdef DEBUG
246 if (ppidebug & PDB_FOLLOW)
247 printf("ppiclose(%x, %x): flags %x\n",
248 dev, flags, sc->sc_flags);
249 #endif
250 sc->sc_flags &= ~PPIF_OPEN;
251 return(0);
252 }
253
254 void
255 ppistart(arg)
256 void *arg;
257 {
258 struct ppi_softc *sc = arg;
259
260 #ifdef DEBUG
261 if (ppidebug & PDB_FOLLOW)
262 printf("ppistart(%x)\n", sc->sc_dev.dv_unit);
263 #endif
264 sc->sc_flags &= ~PPIF_DELAY;
265 wakeup(sc);
266 }
267
268 void
269 ppitimo(arg)
270 void *arg;
271 {
272 struct ppi_softc *sc = arg;
273
274 #ifdef DEBUG
275 if (ppidebug & PDB_FOLLOW)
276 printf("ppitimo(%x)\n", sc->sc_dev.dv_unit);
277 #endif
278 sc->sc_flags &= ~(PPIF_UIO|PPIF_TIMO);
279 wakeup(sc);
280 }
281
282 int
283 ppiread(dev, uio, flags)
284 dev_t dev;
285 struct uio *uio;
286 int flags;
287 {
288
289 #ifdef DEBUG
290 if (ppidebug & PDB_FOLLOW)
291 printf("ppiread(%x, %p)\n", dev, uio);
292 #endif
293 return (ppirw(dev, uio));
294 }
295
296 int
297 ppiwrite(dev, uio, flags)
298 dev_t dev;
299 struct uio *uio;
300 int flags;
301 {
302
303 #ifdef DEBUG
304 if (ppidebug & PDB_FOLLOW)
305 printf("ppiwrite(%x, %p)\n", dev, uio);
306 #endif
307 return (ppirw(dev, uio));
308 }
309
310 int
311 ppirw(dev, uio)
312 dev_t dev;
313 struct uio *uio;
314 {
315 int unit = UNIT(dev);
316 struct ppi_softc *sc = ppi_cd.cd_devs[unit];
317 int s, len, cnt;
318 char *cp;
319 int error = 0, gotdata = 0;
320 int buflen, ctlr, slave;
321 char *buf;
322
323 if (uio->uio_resid == 0)
324 return(0);
325
326 ctlr = sc->sc_dev.dv_parent->dv_unit;
327 slave = sc->sc_slave;
328
329 #ifdef DEBUG
330 if (ppidebug & (PDB_FOLLOW|PDB_IO))
331 printf("ppirw(%x, %p, %c): burst %d, timo %d, resid %x\n",
332 dev, uio, uio->uio_rw == UIO_READ ? 'R' : 'W',
333 sc->sc_burst, sc->sc_timo, uio->uio_resid);
334 #endif
335 buflen = min(sc->sc_burst, uio->uio_resid);
336 buf = (char *)malloc(buflen, M_DEVBUF, M_WAITOK);
337 sc->sc_flags |= PPIF_UIO;
338 if (sc->sc_timo > 0) {
339 sc->sc_flags |= PPIF_TIMO;
340 callout_reset(&sc->sc_timo_ch, sc->sc_timo, ppitimo, sc);
341 }
342 len = cnt = 0;
343 while (uio->uio_resid > 0) {
344 len = min(buflen, uio->uio_resid);
345 cp = buf;
346 if (uio->uio_rw == UIO_WRITE) {
347 error = uiomove(cp, len, uio);
348 if (error)
349 break;
350 }
351 again:
352 s = splbio();
353 if ((sc->sc_flags & PPIF_UIO) &&
354 hpibreq(sc->sc_dev.dv_parent, &sc->sc_hq) == 0)
355 (void) tsleep(sc, PRIBIO + 1, "ppirw", 0);
356 /*
357 * Check if we timed out during sleep or uiomove
358 */
359 (void) spllowersoftclock();
360 if ((sc->sc_flags & PPIF_UIO) == 0) {
361 #ifdef DEBUG
362 if (ppidebug & PDB_IO)
363 printf("ppirw: uiomove/sleep timo, flags %x\n",
364 sc->sc_flags);
365 #endif
366 if (sc->sc_flags & PPIF_TIMO) {
367 callout_stop(&sc->sc_timo_ch);
368 sc->sc_flags &= ~PPIF_TIMO;
369 }
370 splx(s);
371 break;
372 }
373 splx(s);
374 /*
375 * Perform the operation
376 */
377 if (uio->uio_rw == UIO_WRITE)
378 cnt = hpibsend(ctlr, slave, sc->sc_sec, cp, len);
379 else
380 cnt = hpibrecv(ctlr, slave, sc->sc_sec, cp, len);
381 s = splbio();
382 hpibfree(sc->sc_dev.dv_parent, &sc->sc_hq);
383 #ifdef DEBUG
384 if (ppidebug & PDB_IO)
385 printf("ppirw: %s(%d, %d, %x, %p, %d) -> %d\n",
386 uio->uio_rw == UIO_READ ? "recv" : "send",
387 ctlr, slave, sc->sc_sec, cp, len, cnt);
388 #endif
389 splx(s);
390 if (uio->uio_rw == UIO_READ) {
391 if (cnt) {
392 error = uiomove(cp, cnt, uio);
393 if (error)
394 break;
395 gotdata++;
396 }
397 /*
398 * Didn't get anything this time, but did in the past.
399 * Consider us done.
400 */
401 else if (gotdata)
402 break;
403 }
404 s = splsoftclock();
405 /*
406 * Operation timeout (or non-blocking), quit now.
407 */
408 if ((sc->sc_flags & PPIF_UIO) == 0) {
409 #ifdef DEBUG
410 if (ppidebug & PDB_IO)
411 printf("ppirw: timeout/done\n");
412 #endif
413 splx(s);
414 break;
415 }
416 /*
417 * Implement inter-read delay
418 */
419 if (sc->sc_delay > 0) {
420 sc->sc_flags |= PPIF_DELAY;
421 callout_reset(&sc->sc_start_ch, sc->sc_delay,
422 ppistart, sc);
423 error = tsleep(sc, (PCATCH|PZERO) + 1, "hpib", 0);
424 if (error) {
425 splx(s);
426 break;
427 }
428 }
429 splx(s);
430 /*
431 * Must not call uiomove again til we've used all data
432 * that we already grabbed.
433 */
434 if (uio->uio_rw == UIO_WRITE && cnt != len) {
435 cp += cnt;
436 len -= cnt;
437 cnt = 0;
438 goto again;
439 }
440 }
441 s = splsoftclock();
442 if (sc->sc_flags & PPIF_TIMO) {
443 callout_stop(&sc->sc_timo_ch);
444 sc->sc_flags &= ~PPIF_TIMO;
445 }
446 if (sc->sc_flags & PPIF_DELAY) {
447 callout_stop(&sc->sc_start_ch);
448 sc->sc_flags &= ~PPIF_DELAY;
449 }
450 splx(s);
451 /*
452 * Adjust for those chars that we uiomove'ed but never wrote
453 */
454 if (uio->uio_rw == UIO_WRITE && cnt != len) {
455 uio->uio_resid += (len - cnt);
456 #ifdef DEBUG
457 if (ppidebug & PDB_IO)
458 printf("ppirw: short write, adjust by %d\n",
459 len-cnt);
460 #endif
461 }
462 free(buf, M_DEVBUF);
463 #ifdef DEBUG
464 if (ppidebug & (PDB_FOLLOW|PDB_IO))
465 printf("ppirw: return %d, resid %d\n", error, uio->uio_resid);
466 #endif
467 return (error);
468 }
469
470 int
471 ppiioctl(dev, cmd, data, flag, p)
472 dev_t dev;
473 u_long cmd;
474 caddr_t data;
475 int flag;
476 struct proc *p;
477 {
478 struct ppi_softc *sc = ppi_cd.cd_devs[UNIT(dev)];
479 struct ppiparam *pp, *upp;
480 int error = 0;
481
482 switch (cmd) {
483 case PPIIOCGPARAM:
484 pp = &sc->sc_param;
485 upp = (struct ppiparam *)data;
486 upp->burst = pp->burst;
487 upp->timo = ppihztoms(pp->timo);
488 upp->delay = ppihztoms(pp->delay);
489 break;
490 case PPIIOCSPARAM:
491 pp = &sc->sc_param;
492 upp = (struct ppiparam *)data;
493 if (upp->burst < PPI_BURST_MIN || upp->burst > PPI_BURST_MAX ||
494 upp->delay < PPI_DELAY_MIN || upp->delay > PPI_DELAY_MAX)
495 return(EINVAL);
496 pp->burst = upp->burst;
497 pp->timo = ppimstohz(upp->timo);
498 pp->delay = ppimstohz(upp->delay);
499 break;
500 case PPIIOCSSEC:
501 sc->sc_sec = *(int *)data;
502 break;
503 default:
504 return(EINVAL);
505 }
506 return (error);
507 }
508
509 int
510 ppihztoms(h)
511 int h;
512 {
513 extern int hz;
514 int m = h;
515
516 if (m > 0)
517 m = m * 1000 / hz;
518 return(m);
519 }
520
521 int
522 ppimstohz(m)
523 int m;
524 {
525 extern int hz;
526 int h = m;
527
528 if (h > 0) {
529 h = h * hz / 1000;
530 if (h == 0)
531 h = 1000 / hz;
532 }
533 return(h);
534 }
535