par.c revision 1.29 1 /* $NetBSD: par.c,v 1.29 2002/10/23 09:10:35 jdolecek Exp $ */
2
3 /*
4 * Copyright (c) 1982, 1990 The Regents of the University of California.
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. All advertising materials mentioning features or use of this software
16 * must display the following acknowledgement:
17 * This product includes software developed by the University of
18 * California, Berkeley and its contributors.
19 * 4. Neither the name of the University nor the names of its contributors
20 * may be used to endorse or promote products derived from this software
21 * without specific prior written permission.
22 *
23 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 * SUCH DAMAGE.
34 *
35 * @(#)ppi.c 7.3 (Berkeley) 12/16/90
36 */
37
38 #include <sys/cdefs.h>
39 __KERNEL_RCSID(0, "$NetBSD: par.c,v 1.29 2002/10/23 09:10:35 jdolecek Exp $");
40
41 /*
42 * parallel port interface
43 */
44
45 #include "par.h"
46 #if NPAR > 0
47
48 #include <sys/param.h>
49 #include <sys/errno.h>
50 #include <sys/uio.h>
51 #include <sys/device.h>
52 #include <sys/malloc.h>
53 #include <sys/file.h>
54 #include <sys/systm.h>
55 #include <sys/callout.h>
56 #include <sys/proc.h>
57 #include <sys/conf.h>
58
59 #include <amiga/amiga/device.h>
60 #include <amiga/amiga/cia.h>
61 #include <amiga/dev/parioctl.h>
62
63 struct par_softc {
64 struct device sc_dev;
65
66 int sc_flags;
67 struct parparam sc_param;
68 #define sc_burst sc_param.burst
69 #define sc_timo sc_param.timo
70 #define sc_delay sc_param.delay
71
72 struct callout sc_timo_ch;
73 struct callout sc_start_ch;
74 } *par_softcp;
75
76 #define getparsp(x) (x > 0 ? NULL : par_softcp)
77
78 /* sc_flags values */
79 #define PARF_ALIVE 0x01
80 #define PARF_OPEN 0x02
81 #define PARF_UIO 0x04
82 #define PARF_TIMO 0x08
83 #define PARF_DELAY 0x10
84 #define PARF_OREAD 0x40
85 #define PARF_OWRITE 0x80
86
87 #define UNIT(x) minor(x)
88
89 #ifdef DEBUG
90 int pardebug = 0;
91 #define PDB_FOLLOW 0x01
92 #define PDB_IO 0x02
93 #define PDB_INTERRUPT 0x04
94 #define PDB_NOCHECK 0x80
95 #endif
96
97 int parrw(dev_t, struct uio *);
98 int parhztoms(int);
99 int parmstohz(int);
100 int parsend(u_char *, int);
101 int parreceive(u_char *, int);
102 int parsendch(u_char);
103
104 void partimo(void *);
105 void parstart(void *);
106 void parintr(void *);
107
108 void parattach(struct device *, struct device *, void *);
109 int parmatch(struct device *, struct cfdata *, void *);
110
111 CFATTACH_DECL(par, sizeof(struct par_softc),
112 parmatch, parattach, NULL, NULL);
113
114 dev_type_open(paropen);
115 dev_type_close(parclose);
116 dev_type_read(parread);
117 dev_type_write(parwrite);
118 dev_type_ioctl(parioctl);
119
120 const struct cdevsw par_cdevsw = {
121 paropen, parclose, parread, parwrite, parioctl,
122 nostop, notty, nopoll, nommap, nokqfilter,
123 };
124
125 /*ARGSUSED*/
126 int
127 parmatch(struct device *pdp, struct cfdata *cfp, void *auxp)
128 {
129 static int par_found = 0;
130
131 if (!matchname((char *)auxp, "par") || par_found)
132 return(0);
133
134 par_found = 1;
135 return(1);
136 }
137
138 void
139 parattach(struct device *pdp, struct device *dp, void *auxp)
140 {
141 par_softcp = (struct par_softc *)dp;
142
143 #ifdef DEBUG
144 if ((pardebug & PDB_NOCHECK) == 0)
145 #endif
146 par_softcp->sc_flags = PARF_ALIVE;
147 printf("\n");
148
149 callout_init(&par_softcp->sc_timo_ch);
150 callout_init(&par_softcp->sc_start_ch);
151 }
152
153 int
154 paropen(dev_t dev, int flags, int mode, struct proc *p)
155 {
156 int unit = UNIT(dev);
157 struct par_softc *sc = getparsp(unit);
158
159 if (unit >= NPAR || (sc->sc_flags & PARF_ALIVE) == 0)
160 return(ENXIO);
161 #ifdef DEBUG
162 if (pardebug & PDB_FOLLOW) {
163 printf("paropen(%x, %x): flags %x, ",
164 dev, flags, sc->sc_flags);
165 printf ("port = $%x\n", ((ciab.pra ^ CIAB_PRA_SEL)
166 & (CIAB_PRA_SEL|CIAB_PRA_BUSY|CIAB_PRA_POUT)));
167 }
168 #endif
169 if (sc->sc_flags & PARF_OPEN)
170 return(EBUSY);
171 /* can either read or write, but not both */
172 if ((flags & (FREAD|FWRITE)) == (FREAD|FWRITE))
173 return EINVAL;
174
175 sc->sc_flags |= PARF_OPEN;
176
177 if (flags & FREAD)
178 sc->sc_flags |= PARF_OREAD;
179 else
180 sc->sc_flags |= PARF_OWRITE;
181
182 sc->sc_burst = PAR_BURST;
183 sc->sc_timo = parmstohz(PAR_TIMO);
184 sc->sc_delay = parmstohz(PAR_DELAY);
185 /* enable interrupts for CIAA-FLG */
186 ciaa.icr = CIA_ICR_IR_SC | CIA_ICR_FLG;
187 return(0);
188 }
189
190 int
191 parclose(dev_t dev, int flags, int mode, struct proc *p)
192 {
193 int unit = UNIT(dev);
194 struct par_softc *sc = getparsp(unit);
195
196 #ifdef DEBUG
197 if (pardebug & PDB_FOLLOW)
198 printf("parclose(%x, %x): flags %x\n",
199 dev, flags, sc->sc_flags);
200 #endif
201 sc->sc_flags &= ~(PARF_OPEN|PARF_OREAD|PARF_OWRITE);
202 /* don't allow interrupts for CIAA-FLG any longer */
203 ciaa.icr = CIA_ICR_FLG;
204 return(0);
205 }
206
207 void
208 parstart(void *arg)
209 {
210 struct par_softc *sc = arg;
211
212 #ifdef DEBUG
213 if (pardebug & PDB_FOLLOW)
214 printf("parstart(%x)\n", sc->sc_dev.dv_unit);
215 #endif
216 sc->sc_flags &= ~PARF_DELAY;
217 wakeup(sc);
218 }
219
220 void
221 partimo(void *arg)
222 {
223 struct par_softc *sc = arg;
224
225 #ifdef DEBUG
226 if (pardebug & PDB_FOLLOW)
227 printf("partimo(%x)\n", sc->sc_dev.dv_unit);
228 #endif
229 sc->sc_flags &= ~(PARF_UIO|PARF_TIMO);
230 wakeup(sc);
231 }
232
233 int
234 parread(dev_t dev, struct uio *uio, int flags)
235 {
236
237 #ifdef DEBUG
238 if (pardebug & PDB_FOLLOW)
239 printf("parread(%x, %p)\n", dev, uio);
240 #endif
241 return (parrw(dev, uio));
242 }
243
244
245 int
246 parwrite(dev_t dev, struct uio *uio, int flags)
247 {
248
249 #ifdef DEBUG
250 if (pardebug & PDB_FOLLOW)
251 printf("parwrite(%x, %p)\n", dev, uio);
252 #endif
253 return (parrw(dev, uio));
254 }
255
256
257 int
258 parrw(dev_t dev, register struct uio *uio)
259 {
260 int unit = UNIT(dev);
261 register struct par_softc *sc = getparsp(unit);
262 register int s, len, cnt;
263 register char *cp;
264 int error = 0, gotdata = 0;
265 int buflen;
266 char *buf;
267
268 len = 0;
269 cnt = 0;
270 if (!!(sc->sc_flags & PARF_OREAD) ^ (uio->uio_rw == UIO_READ))
271 return EINVAL;
272
273 if (uio->uio_resid == 0)
274 return(0);
275
276 #ifdef DEBUG
277 if (pardebug & (PDB_FOLLOW|PDB_IO))
278 printf("parrw(%x, %p, %c): burst %d, timo %d, resid %x\n",
279 dev, uio, uio->uio_rw == UIO_READ ? 'R' : 'W',
280 sc->sc_burst, sc->sc_timo, uio->uio_resid);
281 #endif
282 buflen = min(sc->sc_burst, uio->uio_resid);
283 buf = (char *)malloc(buflen, M_DEVBUF, M_WAITOK);
284 sc->sc_flags |= PARF_UIO;
285 if (sc->sc_timo > 0)
286 {
287 sc->sc_flags |= PARF_TIMO;
288 callout_reset(&sc->sc_timo_ch, sc->sc_timo, partimo, sc);
289 }
290 while (uio->uio_resid > 0)
291 {
292 len = min(buflen, uio->uio_resid);
293 cp = buf;
294 if (uio->uio_rw == UIO_WRITE)
295 {
296 error = uiomove(cp, len, uio);
297 if (error)
298 break;
299 }
300 again:
301 s = splbio();
302 #if 0
303 if ((sc->sc_flags & PARF_UIO) && hpibreq(&sc->sc_dq) == 0)
304 sleep(sc, PRIBIO+1);
305 #endif
306 /*
307 * Check if we timed out during sleep or uiomove
308 */
309 (void) spllowersoftclock();
310 if ((sc->sc_flags & PARF_UIO) == 0)
311 {
312 #ifdef DEBUG
313 if (pardebug & PDB_IO)
314 printf("parrw: uiomove/sleep timo, flags %x\n",
315 sc->sc_flags);
316 #endif
317 if (sc->sc_flags & PARF_TIMO)
318 {
319 callout_stop(&sc->sc_timo_ch);
320 sc->sc_flags &= ~PARF_TIMO;
321 }
322 splx(s);
323 break;
324 }
325 splx(s);
326 /*
327 * Perform the operation
328 */
329 if (uio->uio_rw == UIO_WRITE)
330 cnt = parsend (cp, len);
331 else
332 cnt = parreceive (cp, len);
333
334 if (cnt < 0)
335 {
336 error = -cnt;
337 break;
338 }
339
340 s = splbio();
341 #if 0
342 hpibfree(&sc->sc_dq);
343 #endif
344 #ifdef DEBUG
345 if (pardebug & PDB_IO)
346 printf("parrw: %s(%p, %d) -> %d\n",
347 uio->uio_rw == UIO_READ ? "recv" : "send", cp, len, cnt);
348 #endif
349 splx(s);
350 if (uio->uio_rw == UIO_READ)
351 {
352 if (cnt)
353 {
354 error = uiomove(cp, cnt, uio);
355 if (error)
356 break;
357 gotdata++;
358 }
359 /*
360 * Didn't get anything this time, but did in the past.
361 * Consider us done.
362 */
363 else if (gotdata)
364 break;
365 }
366 s = splsoftclock();
367 /*
368 * Operation timeout (or non-blocking), quit now.
369 */
370 if ((sc->sc_flags & PARF_UIO) == 0)
371 {
372 #ifdef DEBUG
373 if (pardebug & PDB_IO)
374 printf("parrw: timeout/done\n");
375 #endif
376 splx(s);
377 break;
378 }
379 /*
380 * Implement inter-read delay
381 */
382 if (sc->sc_delay > 0)
383 {
384 sc->sc_flags |= PARF_DELAY;
385 callout_reset(&sc->sc_start_ch, sc->sc_delay, parstart, sc);
386 error = tsleep(sc, PCATCH | (PZERO - 1), "par-cdelay", 0);
387 if (error)
388 {
389 splx(s);
390 break;
391 }
392 }
393 splx(s);
394 /*
395 * Must not call uiomove again til we've used all data
396 * that we already grabbed.
397 */
398 if (uio->uio_rw == UIO_WRITE && cnt != len)
399 {
400 cp += cnt;
401 len -= cnt;
402 cnt = 0;
403 goto again;
404 }
405 }
406 s = splsoftclock();
407 if (sc->sc_flags & PARF_TIMO)
408 {
409 callout_stop(&sc->sc_timo_ch);
410 sc->sc_flags &= ~PARF_TIMO;
411 }
412 if (sc->sc_flags & PARF_DELAY)
413 {
414 callout_stop(&sc->sc_start_ch);
415 sc->sc_flags &= ~PARF_DELAY;
416 }
417 splx(s);
418 /*
419 * Adjust for those chars that we uiomove'ed but never wrote
420 */
421 if (uio->uio_rw == UIO_WRITE && cnt != len)
422 {
423 uio->uio_resid += (len - cnt);
424 #ifdef DEBUG
425 if (pardebug & PDB_IO)
426 printf("parrw: short write, adjust by %d\n",
427 len-cnt);
428 #endif
429 }
430 free(buf, M_DEVBUF);
431 #ifdef DEBUG
432 if (pardebug & (PDB_FOLLOW|PDB_IO))
433 printf("parrw: return %d, resid %d\n", error, uio->uio_resid);
434 #endif
435 return (error);
436 }
437
438 int
439 parioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p)
440 {
441 struct par_softc *sc = getparsp(UNIT(dev));
442 struct parparam *pp, *upp;
443 int error = 0;
444
445 switch (cmd)
446 {
447 case PARIOCGPARAM:
448 pp = &sc->sc_param;
449 upp = (struct parparam *)data;
450 upp->burst = pp->burst;
451 upp->timo = parhztoms(pp->timo);
452 upp->delay = parhztoms(pp->delay);
453 break;
454
455 case PARIOCSPARAM:
456 pp = &sc->sc_param;
457 upp = (struct parparam *)data;
458 if (upp->burst < PAR_BURST_MIN || upp->burst > PAR_BURST_MAX ||
459 upp->delay < PAR_DELAY_MIN || upp->delay > PAR_DELAY_MAX)
460 return(EINVAL);
461 pp->burst = upp->burst;
462 pp->timo = parmstohz(upp->timo);
463 pp->delay = parmstohz(upp->delay);
464 break;
465
466 default:
467 return(EINVAL);
468 }
469 return (error);
470 }
471
472 int
473 parhztoms(int h)
474 {
475 extern int hz;
476 register int m = h;
477
478 if (m > 0)
479 m = m * 1000 / hz;
480 return(m);
481 }
482
483 int
484 parmstohz(int m)
485 {
486 extern int hz;
487 register int h = m;
488
489 if (h > 0) {
490 h = h * hz / 1000;
491 if (h == 0)
492 h = 1000 / hz;
493 }
494 return(h);
495 }
496
497 /* stuff below here if for interrupt driven output of data thru
498 the parallel port. */
499
500 int parsend_pending;
501
502 void
503 parintr(void *arg)
504 {
505 int s;
506
507 s = splclock();
508
509 #ifdef DEBUG
510 if (pardebug & PDB_INTERRUPT)
511 printf("parintr\n");
512 #endif
513 parsend_pending = 0;
514
515 wakeup(parintr);
516 splx(s);
517 }
518
519 int
520 parsendch (u_char ch)
521 {
522 int error = 0;
523 int s;
524
525 /* if either offline, busy or out of paper, wait for that
526 condition to clear */
527 s = splclock();
528 while (!error
529 && (parsend_pending
530 || ((ciab.pra ^ CIAB_PRA_SEL)
531 & (CIAB_PRA_SEL|CIAB_PRA_BUSY|CIAB_PRA_POUT))))
532 {
533 extern int hz;
534
535 #ifdef DEBUG
536 if (pardebug & PDB_INTERRUPT)
537 printf ("parsendch, port = $%x\n",
538 ((ciab.pra ^ CIAB_PRA_SEL)
539 & (CIAB_PRA_SEL|CIAB_PRA_BUSY|CIAB_PRA_POUT)));
540 #endif
541 /* this is essentially a flipflop to have us wait for the
542 first character being transmitted when trying to transmit
543 the second, etc. */
544 parsend_pending = 0;
545 /* it's quite important that a parallel putc can be
546 interrupted, given the possibility to lock a printer
547 in an offline condition.. */
548 error = tsleep(parintr, PCATCH | (PZERO - 1), "parsendch", hz);
549 if (error == EWOULDBLOCK)
550 error = 0;
551 if (error > 0)
552 {
553 #ifdef DEBUG
554 if (pardebug & PDB_INTERRUPT)
555 printf ("parsendch interrupted, error = %d\n", error);
556 #endif
557 }
558 }
559
560 if (! error)
561 {
562 #ifdef DEBUG
563 if (pardebug & PDB_INTERRUPT)
564 printf ("#%d", ch);
565 #endif
566 ciaa.prb = ch;
567 parsend_pending = 1;
568 }
569
570 splx (s);
571
572 return error;
573 }
574
575
576 int
577 parsend (u_char *buf, int len)
578 {
579 int err, orig_len = len;
580
581 /* make sure I/O lines are setup right for output */
582
583 /* control lines set to input */
584 ciab.ddra &= ~(CIAB_PRA_SEL|CIAB_PRA_POUT|CIAB_PRA_BUSY);
585 /* data lines to output */
586 ciaa.ddrb = 0xff;
587
588 for (; len; len--, buf++)
589 if ((err = parsendch (*buf)) != 0)
590 return err < 0 ? -EINTR : -err;
591
592 /* either all or nothing.. */
593 return orig_len;
594 }
595
596
597
598 int
599 parreceive (u_char *buf, int len)
600 {
601 /* oh deary me, something's gotta be left to be implemented
602 later... */
603 return 0;
604 }
605
606
607 #endif
608