Commit | Line | Data |
---|---|---|
60f56dfc | 1 | /* |
66ba08f6 KB |
2 | * Copyright (c) 1982, 1990, 1993 |
3 | * The Regents of the University of California. All rights reserved. | |
60f56dfc KM |
4 | * |
5 | * %sccs.include.redist.c% | |
6 | * | |
66ba08f6 | 7 | * @(#)ppi.c 8.1 (Berkeley) %G% |
60f56dfc KM |
8 | */ |
9 | ||
10 | /* | |
11 | * Printer/Plotter HPIB interface | |
12 | */ | |
13 | ||
14 | #include "ppi.h" | |
15 | #if NPPI > 0 | |
16 | ||
38a01dbe KB |
17 | #include <sys/param.h> |
18 | #include <sys/systm.h> | |
19 | #include <sys/errno.h> | |
20 | #include <sys/uio.h> | |
21 | #include <sys/malloc.h> | |
60f56dfc | 22 | |
38a01dbe KB |
23 | #include <hp/dev/device.h> |
24 | #include <hp300/dev/ppiioctl.h> | |
60f56dfc | 25 | |
ef4c025f KM |
26 | int ppiattach(), ppistart(); |
27 | void ppitimo(); | |
60f56dfc KM |
28 | struct driver ppidriver = { |
29 | ppiattach, "ppi", ppistart, | |
30 | }; | |
31 | ||
32 | struct ppi_softc { | |
33 | int sc_flags; | |
34 | struct devqueue sc_dq; | |
35 | struct hp_device *sc_hd; | |
a47d912d KM |
36 | struct ppiparam sc_param; |
37 | #define sc_burst sc_param.burst | |
38 | #define sc_timo sc_param.timo | |
39 | #define sc_delay sc_param.delay | |
40 | int sc_sec; | |
60f56dfc KM |
41 | } ppi_softc[NPPI]; |
42 | ||
43 | /* sc_flags values */ | |
a47d912d KM |
44 | #define PPIF_ALIVE 0x01 |
45 | #define PPIF_OPEN 0x02 | |
46 | #define PPIF_UIO 0x04 | |
47 | #define PPIF_TIMO 0x08 | |
48 | #define PPIF_DELAY 0x10 | |
60f56dfc KM |
49 | |
50 | #define UNIT(x) minor(x) | |
51 | ||
a47d912d KM |
52 | #ifdef DEBUG |
53 | int ppidebug = 0x80; | |
54 | #define PDB_FOLLOW 0x01 | |
55 | #define PDB_IO 0x02 | |
56 | #define PDB_NOCHECK 0x80 | |
57 | #endif | |
58 | ||
60f56dfc KM |
59 | ppiattach(hd) |
60 | register struct hp_device *hd; | |
61 | { | |
62 | register struct ppi_softc *sc = &ppi_softc[hd->hp_unit]; | |
63 | ||
a47d912d KM |
64 | #ifdef DEBUG |
65 | if ((ppidebug & PDB_NOCHECK) == 0) | |
66 | #endif | |
60f56dfc KM |
67 | /* |
68 | * XXX: the printer/plotter doesn't seem to really return | |
69 | * an ID but this will at least prevent us from mistaking | |
70 | * a cs80 disk or tape for a ppi device. | |
71 | */ | |
72 | if (hpibid(hd->hp_ctlr, hd->hp_slave) & 0x200) | |
73 | return(0); | |
74 | sc->sc_flags = PPIF_ALIVE; | |
75 | sc->sc_dq.dq_ctlr = hd->hp_ctlr; | |
76 | sc->sc_dq.dq_unit = hd->hp_unit; | |
77 | sc->sc_dq.dq_slave = hd->hp_slave; | |
78 | sc->sc_dq.dq_driver = &ppidriver; | |
79 | sc->sc_hd = hd; | |
80 | return(1); | |
81 | } | |
82 | ||
83 | ppiopen(dev, flags) | |
84 | dev_t dev; | |
85 | { | |
86 | register int unit = UNIT(dev); | |
87 | register struct ppi_softc *sc = &ppi_softc[unit]; | |
88 | ||
89 | if (unit >= NPPI || (sc->sc_flags & PPIF_ALIVE) == 0) | |
90 | return(ENXIO); | |
a47d912d KM |
91 | #ifdef DEBUG |
92 | if (ppidebug & PDB_FOLLOW) | |
93 | printf("ppiopen(%x, %x): flags %x\n", | |
94 | dev, flags, sc->sc_flags); | |
95 | #endif | |
60f56dfc KM |
96 | if (sc->sc_flags & PPIF_OPEN) |
97 | return(EBUSY); | |
98 | sc->sc_flags |= PPIF_OPEN; | |
a47d912d KM |
99 | sc->sc_burst = PPI_BURST; |
100 | sc->sc_timo = ppimstohz(PPI_TIMO); | |
101 | sc->sc_delay = ppimstohz(PPI_DELAY); | |
102 | sc->sc_sec = -1; | |
60f56dfc KM |
103 | return(0); |
104 | } | |
105 | ||
106 | ppiclose(dev, flags) | |
107 | dev_t dev; | |
108 | { | |
109 | register int unit = UNIT(dev); | |
110 | register struct ppi_softc *sc = &ppi_softc[unit]; | |
111 | ||
a47d912d KM |
112 | #ifdef DEBUG |
113 | if (ppidebug & PDB_FOLLOW) | |
114 | printf("ppiclose(%x, %x): flags %x\n", | |
115 | dev, flags, sc->sc_flags); | |
116 | #endif | |
60f56dfc KM |
117 | sc->sc_flags &= ~PPIF_OPEN; |
118 | return(0); | |
119 | } | |
120 | ||
121 | ppistart(unit) | |
a47d912d KM |
122 | int unit; |
123 | { | |
124 | #ifdef DEBUG | |
125 | if (ppidebug & PDB_FOLLOW) | |
126 | printf("ppistart(%x)\n", unit); | |
127 | #endif | |
128 | ppi_softc[unit].sc_flags &= ~PPIF_DELAY; | |
129 | wakeup(&ppi_softc[unit]); | |
ef4c025f | 130 | return (0); |
a47d912d KM |
131 | } |
132 | ||
ef4c025f | 133 | void |
a47d912d KM |
134 | ppitimo(unit) |
135 | int unit; | |
60f56dfc | 136 | { |
a47d912d KM |
137 | #ifdef DEBUG |
138 | if (ppidebug & PDB_FOLLOW) | |
139 | printf("ppitimo(%x)\n", unit); | |
140 | #endif | |
141 | ppi_softc[unit].sc_flags &= ~(PPIF_UIO|PPIF_TIMO); | |
60f56dfc KM |
142 | wakeup(&ppi_softc[unit]); |
143 | } | |
144 | ||
145 | ppiread(dev, uio) | |
146 | dev_t dev; | |
147 | struct uio *uio; | |
148 | { | |
149 | ||
a47d912d KM |
150 | #ifdef DEBUG |
151 | if (ppidebug & PDB_FOLLOW) | |
152 | printf("ppiread(%x, %x)\n", dev, uio); | |
153 | #endif | |
154 | return (ppirw(dev, uio)); | |
60f56dfc KM |
155 | } |
156 | ||
157 | ppiwrite(dev, uio) | |
158 | dev_t dev; | |
159 | struct uio *uio; | |
160 | { | |
161 | ||
a47d912d KM |
162 | #ifdef DEBUG |
163 | if (ppidebug & PDB_FOLLOW) | |
164 | printf("ppiwrite(%x, %x)\n", dev, uio); | |
165 | #endif | |
166 | return (ppirw(dev, uio)); | |
60f56dfc KM |
167 | } |
168 | ||
a47d912d | 169 | ppirw(dev, uio) |
60f56dfc KM |
170 | dev_t dev; |
171 | register struct uio *uio; | |
60f56dfc | 172 | { |
a47d912d KM |
173 | int unit = UNIT(dev); |
174 | register struct ppi_softc *sc = &ppi_softc[unit]; | |
60f56dfc KM |
175 | register int s, len, cnt; |
176 | register char *cp; | |
a47d912d KM |
177 | int error = 0, gotdata = 0; |
178 | int buflen; | |
179 | char *buf; | |
180 | ||
181 | if (uio->uio_resid == 0) | |
182 | return(0); | |
60f56dfc | 183 | |
a47d912d KM |
184 | #ifdef DEBUG |
185 | if (ppidebug & (PDB_FOLLOW|PDB_IO)) | |
186 | printf("ppirw(%x, %x, %c): burst %d, timo %d, resid %x\n", | |
187 | dev, uio, uio->uio_rw == UIO_READ ? 'R' : 'W', | |
188 | sc->sc_burst, sc->sc_timo, uio->uio_resid); | |
189 | #endif | |
479c0df7 | 190 | buflen = min(sc->sc_burst, uio->uio_resid); |
a47d912d KM |
191 | buf = (char *)malloc(buflen, M_DEVBUF, M_WAITOK); |
192 | sc->sc_flags |= PPIF_UIO; | |
193 | if (sc->sc_timo > 0) { | |
194 | sc->sc_flags |= PPIF_TIMO; | |
ef4c025f | 195 | timeout(ppitimo, (void *)unit, sc->sc_timo); |
a47d912d | 196 | } |
60f56dfc | 197 | while (uio->uio_resid > 0) { |
479c0df7 | 198 | len = min(buflen, uio->uio_resid); |
a47d912d KM |
199 | cp = buf; |
200 | if (uio->uio_rw == UIO_WRITE) { | |
60f56dfc KM |
201 | error = uiomove(cp, len, uio); |
202 | if (error) | |
203 | break; | |
204 | } | |
a47d912d | 205 | again: |
60f56dfc | 206 | s = splbio(); |
a47d912d KM |
207 | if ((sc->sc_flags & PPIF_UIO) && hpibreq(&sc->sc_dq) == 0) |
208 | sleep(sc, PRIBIO+1); | |
209 | /* | |
210 | * Check if we timed out during sleep or uiomove | |
211 | */ | |
212 | (void) splsoftclock(); | |
213 | if ((sc->sc_flags & PPIF_UIO) == 0) { | |
214 | #ifdef DEBUG | |
215 | if (ppidebug & PDB_IO) | |
216 | printf("ppirw: uiomove/sleep timo, flags %x\n", | |
217 | sc->sc_flags); | |
218 | #endif | |
219 | if (sc->sc_flags & PPIF_TIMO) { | |
ef4c025f | 220 | untimeout(ppitimo, (void *)unit); |
a47d912d KM |
221 | sc->sc_flags &= ~PPIF_TIMO; |
222 | } | |
223 | splx(s); | |
224 | break; | |
225 | } | |
60f56dfc | 226 | splx(s); |
a47d912d KM |
227 | /* |
228 | * Perform the operation | |
229 | */ | |
230 | if (uio->uio_rw == UIO_WRITE) | |
60f56dfc | 231 | cnt = hpibsend(sc->sc_hd->hp_ctlr, sc->sc_hd->hp_slave, |
a47d912d | 232 | sc->sc_sec, cp, len); |
60f56dfc KM |
233 | else |
234 | cnt = hpibrecv(sc->sc_hd->hp_ctlr, sc->sc_hd->hp_slave, | |
a47d912d | 235 | sc->sc_sec, cp, len); |
60f56dfc KM |
236 | s = splbio(); |
237 | hpibfree(&sc->sc_dq); | |
a47d912d KM |
238 | #ifdef DEBUG |
239 | if (ppidebug & PDB_IO) | |
240 | printf("ppirw: %s(%d, %d, %x, %x, %d) -> %d\n", | |
241 | uio->uio_rw == UIO_READ ? "recv" : "send", | |
242 | sc->sc_hd->hp_ctlr, sc->sc_hd->hp_slave, | |
243 | sc->sc_sec, cp, len, cnt); | |
244 | #endif | |
60f56dfc | 245 | splx(s); |
a47d912d KM |
246 | if (uio->uio_rw == UIO_READ) { |
247 | if (cnt) { | |
248 | error = uiomove(cp, cnt, uio); | |
249 | if (error) | |
250 | break; | |
251 | gotdata++; | |
252 | } | |
253 | /* | |
254 | * Didn't get anything this time, but did in the past. | |
255 | * Consider us done. | |
256 | */ | |
257 | else if (gotdata) | |
60f56dfc KM |
258 | break; |
259 | } | |
a47d912d KM |
260 | s = splsoftclock(); |
261 | /* | |
262 | * Operation timeout (or non-blocking), quit now. | |
263 | */ | |
264 | if ((sc->sc_flags & PPIF_UIO) == 0) { | |
265 | #ifdef DEBUG | |
266 | if (ppidebug & PDB_IO) | |
267 | printf("ppirw: timeout/done\n"); | |
268 | #endif | |
269 | splx(s); | |
60f56dfc KM |
270 | break; |
271 | } | |
a47d912d KM |
272 | /* |
273 | * Implement inter-read delay | |
274 | */ | |
275 | if (sc->sc_delay > 0) { | |
276 | sc->sc_flags |= PPIF_DELAY; | |
ef4c025f KM |
277 | timeout((void (*)__P((void *)))ppistart, (void *)unit, |
278 | sc->sc_delay); | |
a47d912d KM |
279 | error = tsleep(sc, PCATCH|PZERO+1, "hpib", 0); |
280 | if (error) { | |
281 | splx(s); | |
282 | break; | |
283 | } | |
284 | } | |
285 | splx(s); | |
286 | /* | |
287 | * Must not call uiomove again til we've used all data | |
288 | * that we already grabbed. | |
289 | */ | |
290 | if (uio->uio_rw == UIO_WRITE && cnt != len) { | |
291 | cp += cnt; | |
292 | len -= cnt; | |
293 | cnt = 0; | |
294 | goto again; | |
295 | } | |
296 | } | |
297 | s = splsoftclock(); | |
298 | if (sc->sc_flags & PPIF_TIMO) { | |
ef4c025f | 299 | untimeout(ppitimo, (void *)unit); |
a47d912d KM |
300 | sc->sc_flags &= ~PPIF_TIMO; |
301 | } | |
302 | if (sc->sc_flags & PPIF_DELAY) { | |
ef4c025f | 303 | untimeout((void (*)__P((void *)))ppistart, (void *)unit); |
a47d912d KM |
304 | sc->sc_flags &= ~PPIF_DELAY; |
305 | } | |
306 | splx(s); | |
307 | /* | |
308 | * Adjust for those chars that we uiomove'ed but never wrote | |
309 | */ | |
310 | if (uio->uio_rw == UIO_WRITE && cnt != len) { | |
311 | uio->uio_resid += (len - cnt); | |
312 | #ifdef DEBUG | |
313 | if (ppidebug & PDB_IO) | |
314 | printf("ppirw: short write, adjust by %d\n", | |
315 | len-cnt); | |
316 | #endif | |
317 | } | |
318 | free(buf, M_DEVBUF); | |
319 | #ifdef DEBUG | |
320 | if (ppidebug & (PDB_FOLLOW|PDB_IO)) | |
321 | printf("ppirw: return %d, resid %d\n", error, uio->uio_resid); | |
322 | #endif | |
323 | return (error); | |
324 | } | |
325 | ||
326 | ppiioctl(dev, cmd, data, flag) | |
327 | dev_t dev; | |
328 | int cmd; | |
329 | caddr_t data; | |
330 | int flag; | |
331 | { | |
332 | struct ppi_softc *sc = &ppi_softc[UNIT(dev)]; | |
333 | struct ppiparam *pp, *upp; | |
334 | int error = 0; | |
335 | ||
336 | switch (cmd) { | |
337 | case PPIIOCGPARAM: | |
338 | pp = &sc->sc_param; | |
339 | upp = (struct ppiparam *)data; | |
340 | upp->burst = pp->burst; | |
341 | upp->timo = ppihztoms(pp->timo); | |
342 | upp->delay = ppihztoms(pp->delay); | |
343 | break; | |
344 | case PPIIOCSPARAM: | |
345 | pp = &sc->sc_param; | |
346 | upp = (struct ppiparam *)data; | |
347 | if (upp->burst < PPI_BURST_MIN || upp->burst > PPI_BURST_MAX || | |
348 | upp->delay < PPI_DELAY_MIN || upp->delay > PPI_DELAY_MAX) | |
349 | return(EINVAL); | |
350 | pp->burst = upp->burst; | |
351 | pp->timo = ppimstohz(upp->timo); | |
352 | pp->delay = ppimstohz(upp->delay); | |
353 | break; | |
354 | case PPIIOCSSEC: | |
355 | sc->sc_sec = *(int *)data; | |
356 | break; | |
357 | default: | |
358 | return(EINVAL); | |
60f56dfc | 359 | } |
60f56dfc KM |
360 | return (error); |
361 | } | |
a47d912d KM |
362 | |
363 | ppihztoms(h) | |
364 | int h; | |
365 | { | |
366 | extern int hz; | |
367 | register int m = h; | |
368 | ||
369 | if (m > 0) | |
370 | m = m * 1000 / hz; | |
371 | return(m); | |
372 | } | |
373 | ||
374 | ppimstohz(m) | |
375 | int m; | |
376 | { | |
377 | extern int hz; | |
378 | register int h = m; | |
379 | ||
380 | if (h > 0) { | |
381 | h = h * hz / 1000; | |
382 | if (h == 0) | |
383 | h = 1000 / hz; | |
384 | } | |
385 | return(h); | |
386 | } | |
60f56dfc | 387 | #endif |