ppi.c revision 1.3 1 /*
2 * Copyright (c) 1982, 1990 The Regents of the University of California.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 * must display the following acknowledgement:
15 * This product includes software developed by the University of
16 * California, Berkeley and its contributors.
17 * 4. Neither the name of the University nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 *
33 * from: @(#)ppi.c 7.3 (Berkeley) 12/16/90
34 * $Id: ppi.c,v 1.3 1994/02/10 13:59:37 mycroft Exp $
35 */
36
37 /*
38 * Printer/Plotter HPIB interface
39 */
40
41 #include "ppi.h"
42 #if NPPI > 0
43
44 #include <sys/param.h>
45 #include <sys/systm.h>
46 #include <sys/errno.h>
47 #include <sys/uio.h>
48 #include <sys/malloc.h>
49
50 #include <hp300/dev/device.h>
51 #include <hp300/dev/ppiioctl.h>
52
53 int ppiattach(), ppistart(), ppitimo();
54 struct driver ppidriver = {
55 ppiattach, "ppi", ppistart,
56 };
57
58 struct ppi_softc {
59 int sc_flags;
60 struct devqueue sc_dq;
61 struct hp_device *sc_hd;
62 struct ppiparam sc_param;
63 #define sc_burst sc_param.burst
64 #define sc_timo sc_param.timo
65 #define sc_delay sc_param.delay
66 int sc_sec;
67 } ppi_softc[NPPI];
68
69 /* sc_flags values */
70 #define PPIF_ALIVE 0x01
71 #define PPIF_OPEN 0x02
72 #define PPIF_UIO 0x04
73 #define PPIF_TIMO 0x08
74 #define PPIF_DELAY 0x10
75
76 #define UNIT(x) minor(x)
77
78 #ifdef DEBUG
79 int ppidebug = 0x80;
80 #define PDB_FOLLOW 0x01
81 #define PDB_IO 0x02
82 #define PDB_NOCHECK 0x80
83 #endif
84
85 ppiattach(hd)
86 register struct hp_device *hd;
87 {
88 register struct ppi_softc *sc = &ppi_softc[hd->hp_unit];
89
90 #ifdef DEBUG
91 if ((ppidebug & PDB_NOCHECK) == 0)
92 #endif
93 /*
94 * XXX: the printer/plotter doesn't seem to really return
95 * an ID but this will at least prevent us from mistaking
96 * a cs80 disk or tape for a ppi device.
97 */
98 if (hpibid(hd->hp_ctlr, hd->hp_slave) & 0x200)
99 return(0);
100 sc->sc_flags = PPIF_ALIVE;
101 sc->sc_dq.dq_ctlr = hd->hp_ctlr;
102 sc->sc_dq.dq_unit = hd->hp_unit;
103 sc->sc_dq.dq_slave = hd->hp_slave;
104 sc->sc_dq.dq_driver = &ppidriver;
105 sc->sc_hd = hd;
106 return(1);
107 }
108
109 ppiopen(dev, flags)
110 dev_t dev;
111 {
112 register int unit = UNIT(dev);
113 register struct ppi_softc *sc = &ppi_softc[unit];
114
115 if (unit >= NPPI || (sc->sc_flags & PPIF_ALIVE) == 0)
116 return(ENXIO);
117 #ifdef DEBUG
118 if (ppidebug & PDB_FOLLOW)
119 printf("ppiopen(%x, %x): flags %x\n",
120 dev, flags, sc->sc_flags);
121 #endif
122 if (sc->sc_flags & PPIF_OPEN)
123 return(EBUSY);
124 sc->sc_flags |= PPIF_OPEN;
125 sc->sc_burst = PPI_BURST;
126 sc->sc_timo = ppimstohz(PPI_TIMO);
127 sc->sc_delay = ppimstohz(PPI_DELAY);
128 sc->sc_sec = -1;
129 return(0);
130 }
131
132 ppiclose(dev, flags)
133 dev_t dev;
134 {
135 register int unit = UNIT(dev);
136 register struct ppi_softc *sc = &ppi_softc[unit];
137
138 #ifdef DEBUG
139 if (ppidebug & PDB_FOLLOW)
140 printf("ppiclose(%x, %x): flags %x\n",
141 dev, flags, sc->sc_flags);
142 #endif
143 sc->sc_flags &= ~PPIF_OPEN;
144 return(0);
145 }
146
147 ppistart(unit)
148 int unit;
149 {
150 #ifdef DEBUG
151 if (ppidebug & PDB_FOLLOW)
152 printf("ppistart(%x)\n", unit);
153 #endif
154 ppi_softc[unit].sc_flags &= ~PPIF_DELAY;
155 wakeup(&ppi_softc[unit]);
156 }
157
158 ppitimo(unit)
159 int unit;
160 {
161 #ifdef DEBUG
162 if (ppidebug & PDB_FOLLOW)
163 printf("ppitimo(%x)\n", unit);
164 #endif
165 ppi_softc[unit].sc_flags &= ~(PPIF_UIO|PPIF_TIMO);
166 wakeup(&ppi_softc[unit]);
167 }
168
169 ppiread(dev, uio)
170 dev_t dev;
171 struct uio *uio;
172 {
173
174 #ifdef DEBUG
175 if (ppidebug & PDB_FOLLOW)
176 printf("ppiread(%x, %x)\n", dev, uio);
177 #endif
178 return (ppirw(dev, uio));
179 }
180
181 ppiwrite(dev, uio)
182 dev_t dev;
183 struct uio *uio;
184 {
185
186 #ifdef DEBUG
187 if (ppidebug & PDB_FOLLOW)
188 printf("ppiwrite(%x, %x)\n", dev, uio);
189 #endif
190 return (ppirw(dev, uio));
191 }
192
193 ppirw(dev, uio)
194 dev_t dev;
195 register struct uio *uio;
196 {
197 int unit = UNIT(dev);
198 register struct ppi_softc *sc = &ppi_softc[unit];
199 register int s, len, cnt;
200 register char *cp;
201 int error = 0, gotdata = 0;
202 int buflen;
203 char *buf;
204
205 if (uio->uio_resid == 0)
206 return(0);
207
208 #ifdef DEBUG
209 if (ppidebug & (PDB_FOLLOW|PDB_IO))
210 printf("ppirw(%x, %x, %c): burst %d, timo %d, resid %x\n",
211 dev, uio, uio->uio_rw == UIO_READ ? 'R' : 'W',
212 sc->sc_burst, sc->sc_timo, uio->uio_resid);
213 #endif
214 buflen = MIN(sc->sc_burst, uio->uio_resid);
215 buf = (char *)malloc(buflen, M_DEVBUF, M_WAITOK);
216 sc->sc_flags |= PPIF_UIO;
217 if (sc->sc_timo > 0) {
218 sc->sc_flags |= PPIF_TIMO;
219 timeout(ppitimo, unit, sc->sc_timo);
220 }
221 while (uio->uio_resid > 0) {
222 len = MIN(buflen, uio->uio_resid);
223 cp = buf;
224 if (uio->uio_rw == UIO_WRITE) {
225 error = uiomove(cp, len, uio);
226 if (error)
227 break;
228 }
229 again:
230 s = splbio();
231 if ((sc->sc_flags & PPIF_UIO) && hpibreq(&sc->sc_dq) == 0)
232 sleep(sc, PRIBIO+1);
233 /*
234 * Check if we timed out during sleep or uiomove
235 */
236 (void) splsoftclock();
237 if ((sc->sc_flags & PPIF_UIO) == 0) {
238 #ifdef DEBUG
239 if (ppidebug & PDB_IO)
240 printf("ppirw: uiomove/sleep timo, flags %x\n",
241 sc->sc_flags);
242 #endif
243 if (sc->sc_flags & PPIF_TIMO) {
244 untimeout(ppitimo, unit);
245 sc->sc_flags &= ~PPIF_TIMO;
246 }
247 splx(s);
248 break;
249 }
250 splx(s);
251 /*
252 * Perform the operation
253 */
254 if (uio->uio_rw == UIO_WRITE)
255 cnt = hpibsend(sc->sc_hd->hp_ctlr, sc->sc_hd->hp_slave,
256 sc->sc_sec, cp, len);
257 else
258 cnt = hpibrecv(sc->sc_hd->hp_ctlr, sc->sc_hd->hp_slave,
259 sc->sc_sec, cp, len);
260 s = splbio();
261 hpibfree(&sc->sc_dq);
262 #ifdef DEBUG
263 if (ppidebug & PDB_IO)
264 printf("ppirw: %s(%d, %d, %x, %x, %d) -> %d\n",
265 uio->uio_rw == UIO_READ ? "recv" : "send",
266 sc->sc_hd->hp_ctlr, sc->sc_hd->hp_slave,
267 sc->sc_sec, cp, len, cnt);
268 #endif
269 splx(s);
270 if (uio->uio_rw == UIO_READ) {
271 if (cnt) {
272 error = uiomove(cp, cnt, uio);
273 if (error)
274 break;
275 gotdata++;
276 }
277 /*
278 * Didn't get anything this time, but did in the past.
279 * Consider us done.
280 */
281 else if (gotdata)
282 break;
283 }
284 s = splsoftclock();
285 /*
286 * Operation timeout (or non-blocking), quit now.
287 */
288 if ((sc->sc_flags & PPIF_UIO) == 0) {
289 #ifdef DEBUG
290 if (ppidebug & PDB_IO)
291 printf("ppirw: timeout/done\n");
292 #endif
293 splx(s);
294 break;
295 }
296 /*
297 * Implement inter-read delay
298 */
299 if (sc->sc_delay > 0) {
300 sc->sc_flags |= PPIF_DELAY;
301 timeout(ppistart, unit, sc->sc_delay);
302 error = tsleep(sc, PCATCH|PZERO+1, "hpib", 0);
303 if (error) {
304 splx(s);
305 break;
306 }
307 }
308 splx(s);
309 /*
310 * Must not call uiomove again til we've used all data
311 * that we already grabbed.
312 */
313 if (uio->uio_rw == UIO_WRITE && cnt != len) {
314 cp += cnt;
315 len -= cnt;
316 cnt = 0;
317 goto again;
318 }
319 }
320 s = splsoftclock();
321 if (sc->sc_flags & PPIF_TIMO) {
322 untimeout(ppitimo, unit);
323 sc->sc_flags &= ~PPIF_TIMO;
324 }
325 if (sc->sc_flags & PPIF_DELAY) {
326 untimeout(ppistart, unit);
327 sc->sc_flags &= ~PPIF_DELAY;
328 }
329 splx(s);
330 /*
331 * Adjust for those chars that we uiomove'ed but never wrote
332 */
333 if (uio->uio_rw == UIO_WRITE && cnt != len) {
334 uio->uio_resid += (len - cnt);
335 #ifdef DEBUG
336 if (ppidebug & PDB_IO)
337 printf("ppirw: short write, adjust by %d\n",
338 len-cnt);
339 #endif
340 }
341 free(buf, M_DEVBUF);
342 #ifdef DEBUG
343 if (ppidebug & (PDB_FOLLOW|PDB_IO))
344 printf("ppirw: return %d, resid %d\n", error, uio->uio_resid);
345 #endif
346 return (error);
347 }
348
349 ppiioctl(dev, cmd, data, flag, p)
350 dev_t dev;
351 int cmd;
352 caddr_t data;
353 int flag;
354 struct proc *p;
355 {
356 struct ppi_softc *sc = &ppi_softc[UNIT(dev)];
357 struct ppiparam *pp, *upp;
358 int error = 0;
359
360 switch (cmd) {
361 case PPIIOCGPARAM:
362 pp = &sc->sc_param;
363 upp = (struct ppiparam *)data;
364 upp->burst = pp->burst;
365 upp->timo = ppihztoms(pp->timo);
366 upp->delay = ppihztoms(pp->delay);
367 break;
368 case PPIIOCSPARAM:
369 pp = &sc->sc_param;
370 upp = (struct ppiparam *)data;
371 if (upp->burst < PPI_BURST_MIN || upp->burst > PPI_BURST_MAX ||
372 upp->delay < PPI_DELAY_MIN || upp->delay > PPI_DELAY_MAX)
373 return(EINVAL);
374 pp->burst = upp->burst;
375 pp->timo = ppimstohz(upp->timo);
376 pp->delay = ppimstohz(upp->delay);
377 break;
378 case PPIIOCSSEC:
379 sc->sc_sec = *(int *)data;
380 break;
381 default:
382 return(EINVAL);
383 }
384 return (error);
385 }
386
387 ppihztoms(h)
388 int h;
389 {
390 extern int hz;
391 register int m = h;
392
393 if (m > 0)
394 m = m * 1000 / hz;
395 return(m);
396 }
397
398 ppimstohz(m)
399 int m;
400 {
401 extern int hz;
402 register int h = m;
403
404 if (h > 0) {
405 h = h * hz / 1000;
406 if (h == 0)
407 h = 1000 / hz;
408 }
409 return(h);
410 }
411 #endif
412