par.c revision 1.1 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: par.c,v 1.1 1993/09/02 16:53:40 mw Exp $
35 */
36
37 /*
38 * parallel port interface
39
40 XXXX NOT YET WORKING XXXXX
41 */
42
43 #include "ppi.h"
44 #if NPAR > 0
45
46 #include "sys/param.h"
47 #include "sys/errno.h"
48 #include "sys/uio.h"
49 #include "sys/malloc.h"
50
51 #include "device.h"
52 #include "parioctl.h"
53
54 int parattach(), parstart(), partimo(), parintr();
55 struct driver pardriver = {
56 parattach, "par", parstart,
57 };
58
59 struct par_softc {
60 int sc_flags;
61 struct amiga_device *sc_ad;
62 struct parparam sc_param;
63 #define sc_burst sc_param.burst
64 #define sc_timo sc_param.timo
65 #define sc_delay sc_param.delay
66 } par_softc[NPPI];
67
68 /* sc_flags values */
69 #define PARF_ALIVE 0x01
70 #define PARF_OPEN 0x02
71 #define PARF_UIO 0x04
72 #define PARF_TIMO 0x08
73 #define PARF_DELAY 0x10
74 #define PARF_OREAD 0x40
75 #define PARF_OWRITE 0x80
76
77 #define UNIT(x) minor(x)
78
79 #ifdef DEBUG
80 int pardebug = 0x80;
81 #define PDB_FOLLOW 0x01
82 #define PDB_IO 0x02
83 #define PDB_NOCHECK 0x80
84 #endif
85
86 parattach(ad)
87 register struct amiga_device *ad;
88 {
89 register struct par_softc *sc = &par_softc[ad->amiga_unit];
90
91 #ifdef DEBUG
92 if ((pardebug & PDB_NOCHECK) == 0)
93 #endif
94 sc->sc_flags = PARF_ALIVE;
95 sc->sc_ad = ad;
96 return(1);
97 }
98
99 paropen(dev, flags)
100 dev_t dev;
101 {
102 register int unit = UNIT(dev);
103 register struct par_softc *sc = &par_softc[unit];
104
105 if (unit >= NPAR || (sc->sc_flags & PARF_ALIVE) == 0)
106 return(ENXIO);
107 #ifdef DEBUG
108 if (pardebug & PDB_FOLLOW)
109 printf("paropen(%x, %x): flags %x\n",
110 dev, flags, sc->sc_flags);
111 #endif
112 if (sc->sc_flags & PARF_OPEN)
113 return(EBUSY);
114 /* can either read or write, but not both */
115 if ((flags & (FREAD|FWRITE)) == (FREAD|FWRITE))
116 return EINVAL;
117
118 sc->sc_flags |= PARF_OPEN;
119 if (flags & FREAD)
120 sc->sc_flags |= PARF_OREAD;
121 else
122 sc->sc_flags |= PARF_OWRITE;
123 sc->sc_burst = PAR_BURST;
124 sc->sc_timo = parmstohz(PAR_TIMO);
125 sc->sc_delay = parmstohz(PAR_DELAY);
126 /* enable interrupts for CIAA-FLG */
127 ciaa.icr = CIA_ICR_IR_SC | CIA_ICR_FLG;
128 return(0);
129 }
130
131 parclose(dev, flags)
132 dev_t dev;
133 {
134 register int unit = UNIT(dev);
135 register struct par_softc *sc = &par_softc[unit];
136
137 #ifdef DEBUG
138 if (pardebug & PDB_FOLLOW)
139 printf("parclose(%x, %x): flags %x\n",
140 dev, flags, sc->sc_flags);
141 #endif
142 sc->sc_flags &= ~(PARF_OPEN|PARF_OREAD|PARF_OWRITE);
143 /* don't allow interrupts for CIAA-FLG any longer */
144 ciaa.icr = CIA_ICR_FLG;
145 return(0);
146 }
147
148 parstart(unit)
149 int unit;
150 {
151 #ifdef DEBUG
152 if (pardebug & PDB_FOLLOW)
153 printf("parstart(%x)\n", unit);
154 #endif
155 par_softc[unit].sc_flags &= ~PARF_DELAY;
156 wakeup(&par_softc[unit]);
157 }
158
159 partimo(unit)
160 int unit;
161 {
162 #ifdef DEBUG
163 if (pardebug & PDB_FOLLOW)
164 printf("partimo(%x)\n", unit);
165 #endif
166 par_softc[unit].sc_flags &= ~(PARF_UIO|PARF_TIMO);
167 wakeup(&par_softc[unit]);
168 }
169
170 parread(dev, uio)
171 dev_t dev;
172 struct uio *uio;
173 {
174
175 #ifdef DEBUG
176 if (pardebug & PDB_FOLLOW)
177 printf("parread(%x, %x)\n", dev, uio);
178 #endif
179 return (parrw(dev, uio));
180 }
181
182 parwrite(dev, uio)
183 dev_t dev;
184 struct uio *uio;
185 {
186
187 #ifdef DEBUG
188 if (pardebug & PDB_FOLLOW)
189 printf("parwrite(%x, %x)\n", dev, uio);
190 #endif
191 return (parrw(dev, uio));
192 }
193
194 parrw(dev, uio)
195 dev_t dev;
196 register struct uio *uio;
197 {
198 int unit = UNIT(dev);
199 register struct par_softc *sc = &par_softc[unit];
200 register int s, len, cnt;
201 register char *cp;
202 int error = 0, gotdata = 0;
203 int buflen;
204 char *buf;
205
206 if ((sc->sc_flags & PARF_OREAD) ^^ (uio->uio_rw == UIO_READ))
207 return EINVAL;
208
209 if (uio->uio_resid == 0)
210 return(0);
211
212 #ifdef DEBUG
213 if (pardebug & (PDB_FOLLOW|PDB_IO))
214 printf("parrw(%x, %x, %c): burst %d, timo %d, resid %x\n",
215 dev, uio, uio->uio_rw == UIO_READ ? 'R' : 'W',
216 sc->sc_burst, sc->sc_timo, uio->uio_resid);
217 #endif
218 buflen = MIN(sc->sc_burst, uio->uio_resid);
219 buf = (char *)malloc(buflen, M_DEVBUF, M_WAITOK);
220 sc->sc_flags |= PARF_UIO;
221 if (sc->sc_timo > 0) {
222 sc->sc_flags |= PARF_TIMO;
223 timeout(partimo, unit, sc->sc_timo);
224 }
225 while (uio->uio_resid > 0) {
226 len = MIN(buflen, uio->uio_resid);
227 cp = buf;
228 if (uio->uio_rw == UIO_WRITE) {
229 error = uiomove(cp, len, uio);
230 if (error)
231 break;
232 }
233 again:
234 s = splbio();
235 #if 0
236 if ((sc->sc_flags & PARF_UIO) && hpibreq(&sc->sc_dq) == 0)
237 sleep(sc, PRIBIO+1);
238 #endif
239 /*
240 * Check if we timed out during sleep or uiomove
241 */
242 (void) splsoftclock();
243 if ((sc->sc_flags & PARF_UIO) == 0) {
244 #ifdef DEBUG
245 if (pardebug & PDB_IO)
246 printf("parrw: uiomove/sleep timo, flags %x\n",
247 sc->sc_flags);
248 #endif
249 if (sc->sc_flags & PARF_TIMO) {
250 untimeout(partimo, unit);
251 sc->sc_flags &= ~PARF_TIMO;
252 }
253 splx(s);
254 break;
255 }
256 splx(s);
257 /*
258 * Perform the operation
259 */
260 if (uio->uio_rw == UIO_WRITE)
261 cnt = hpibsend(sc->sc_ad->amiga_ctlr, sc->sc_ad->amiga_slave,
262 sc->sc_sec, cp, len);
263 else
264 cnt = hpibrecv(sc->sc_ad->amiga_ctlr, sc->sc_ad->amiga_slave,
265 sc->sc_sec, cp, len);
266 s = splbio();
267 hpibfree(&sc->sc_dq);
268 #ifdef DEBUG
269 if (pardebug & PDB_IO)
270 printf("parrw: %s(%d, %d, %x, %x, %d) -> %d\n",
271 uio->uio_rw == UIO_READ ? "recv" : "send",
272 sc->sc_ad->amiga_ctlr, sc->sc_ad->amiga_slave,
273 sc->sc_sec, cp, len, cnt);
274 #endif
275 splx(s);
276 if (uio->uio_rw == UIO_READ) {
277 if (cnt) {
278 error = uiomove(cp, cnt, uio);
279 if (error)
280 break;
281 gotdata++;
282 }
283 /*
284 * Didn't get anything this time, but did in the past.
285 * Consider us done.
286 */
287 else if (gotdata)
288 break;
289 }
290 s = splsoftclock();
291 /*
292 * Operation timeout (or non-blocking), quit now.
293 */
294 if ((sc->sc_flags & PARF_UIO) == 0) {
295 #ifdef DEBUG
296 if (pardebug & PDB_IO)
297 printf("parrw: timeout/done\n");
298 #endif
299 splx(s);
300 break;
301 }
302 /*
303 * Implement inter-read delay
304 */
305 if (sc->sc_delay > 0) {
306 sc->sc_flags |= PARF_DELAY;
307 timeout(parstart, unit, sc->sc_delay);
308 error = tsleep(sc, PCATCH|PZERO-1, "par-cdelay", 0);
309 if (error) {
310 splx(s);
311 break;
312 }
313 }
314 splx(s);
315 /*
316 * Must not call uiomove again til we've used all data
317 * that we already grabbed.
318 */
319 if (uio->uio_rw == UIO_WRITE && cnt != len) {
320 cp += cnt;
321 len -= cnt;
322 cnt = 0;
323 goto again;
324 }
325 }
326 s = splsoftclock();
327 if (sc->sc_flags & PARF_TIMO) {
328 untimeout(partimo, unit);
329 sc->sc_flags &= ~PARF_TIMO;
330 }
331 if (sc->sc_flags & PARF_DELAY) {
332 untimeout(parstart, unit);
333 sc->sc_flags &= ~PARF_DELAY;
334 }
335 splx(s);
336 /*
337 * Adjust for those chars that we uiomove'ed but never wrote
338 */
339 if (uio->uio_rw == UIO_WRITE && cnt != len) {
340 uio->uio_resid += (len - cnt);
341 #ifdef DEBUG
342 if (pardebug & PDB_IO)
343 printf("parrw: short write, adjust by %d\n",
344 len-cnt);
345 #endif
346 }
347 free(buf, M_DEVBUF);
348 #ifdef DEBUG
349 if (pardebug & (PDB_FOLLOW|PDB_IO))
350 printf("parrw: return %d, resid %d\n", error, uio->uio_resid);
351 #endif
352 return (error);
353 }
354
355 parioctl(dev, cmd, data, flag)
356 dev_t dev;
357 int cmd;
358 caddr_t data;
359 int flag;
360 {
361 struct par_softc *sc = &par_softc[UNIT(dev)];
362 struct parparam *pp, *upp;
363 int error = 0;
364
365 switch (cmd) {
366 case PARIOCGPARAM:
367 pp = &sc->sc_param;
368 upp = (struct parparam *)data;
369 upp->burst = pp->burst;
370 upp->timo = parhztoms(pp->timo);
371 upp->delay = parhztoms(pp->delay);
372 break;
373 case PARIOCSPARAM:
374 pp = &sc->sc_param;
375 upp = (struct parparam *)data;
376 if (upp->burst < PAR_BURST_MIN || upp->burst > PAR_BURST_MAX ||
377 upp->delay < PAR_DELAY_MIN || upp->delay > PAR_DELAY_MAX)
378 return(EINVAL);
379 pp->burst = upp->burst;
380 pp->timo = parmstohz(upp->timo);
381 pp->delay = parmstohz(upp->delay);
382 break;
383 default:
384 return(EINVAL);
385 }
386 return (error);
387 }
388
389 parhztoms(h)
390 int h;
391 {
392 extern int hz;
393 register int m = h;
394
395 if (m > 0)
396 m = m * 1000 / hz;
397 return(m);
398 }
399
400 parmstohz(m)
401 int m;
402 {
403 extern int hz;
404 register int h = m;
405
406 if (h > 0) {
407 h = h * hz / 1000;
408 if (h == 0)
409 h = 1000 / hz;
410 }
411 return(h);
412 }
413
414 void
415 parintr (mask)
416 int mask;
417 {
418 wakeup (parintr);
419 }
420
421 int
422 parsend (buf, len)
423 u_char *buf;
424 int len;
425 {
426 /* make sure I/O lines are setup right for output */
427
428 /* control lines set to input */
429 ciab.ddra &= ~(CIAB_PRA_SEL|CIAB_PRA_POUT|CIAB_PRA_BUSY);
430 /* data lines to output */
431 ciaa.ddrb = 0xff;
432
433 while (len)
434 {
435
436 }
437 }
438
439
440
441
442
443
444 #endif
445