par.c revision 1.17 1 /* $NetBSD: par.c,v 1.17 2002/10/23 09:12:47 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 /*
39 * parallel port interface
40 */
41
42 #include <sys/param.h>
43 #include <sys/errno.h>
44 #include <sys/uio.h>
45 #include <sys/device.h>
46 #include <sys/malloc.h>
47 #include <sys/file.h>
48 #include <sys/systm.h>
49 #include <sys/callout.h>
50 #include <sys/proc.h>
51 #include <sys/conf.h>
52
53 #include <machine/bus.h>
54 #include <machine/cpu.h>
55 #include <machine/parioctl.h>
56
57 #include <arch/x68k/dev/intiovar.h>
58
59 struct par_softc {
60 struct device sc_dev;
61
62 bus_space_tag_t sc_bst;
63 bus_space_handle_t sc_bsh;
64 int sc_flags;
65 struct parparam sc_param;
66 #define sc_burst sc_param.burst
67 #define sc_timo sc_param.timo
68 #define sc_delay sc_param.delay
69 struct callout sc_timo_ch;
70 struct callout sc_start_ch;
71 } ;
72
73 /* par registers */
74 #define PAR_DATA 1
75 #define PAR_STROBE 3
76
77 /* sc_flags values */
78 #define PARF_ALIVE 0x01
79 #define PARF_OPEN 0x02
80 #define PARF_UIO 0x04
81 #define PARF_TIMO 0x08
82 #define PARF_DELAY 0x10
83 #define PARF_OREAD 0x40 /* no support */
84 #define PARF_OWRITE 0x80
85
86
87 void partimo __P((void *));
88 void parstart __P((void *);)
89 void parintr __P((void *));
90 int parrw __P((dev_t, struct uio *));
91 int parhztoms __P((int));
92 int parmstohz __P((int));
93 int parsendch __P((struct par_softc*, u_char));
94 int parsend __P((struct par_softc*, u_char *, int));
95
96 static struct callout intr_callout = CALLOUT_INITIALIZER;
97
98 #define UNIT(x) minor(x)
99
100 #ifdef DEBUG
101 #define PDB_FOLLOW 0x01
102 #define PDB_IO 0x02
103 #define PDB_INTERRUPT 0x04
104 #define PDB_NOCHECK 0x80
105 #ifdef PARDEBUG
106 int pardebug = PDB_FOLLOW | PDB_IO | PDB_INTERRUPT;
107 #else
108 int pardebug = 0;
109 #endif
110 #endif
111
112 int parmatch __P((struct device *, struct cfdata *, void *));
113 void parattach __P((struct device *, struct device *, void *));
114
115 CFATTACH_DECL(par, sizeof(struct par_softc),
116 parmatch, parattach, NULL, NULL);
117
118 extern struct cfdriver par_cd;
119
120 dev_type_open(paropen);
121 dev_type_close(parclose);
122 dev_type_write(parwrite);
123 dev_type_ioctl(parioctl);
124
125 const struct cdevsw par_cdevsw = {
126 paropen, parclose, noread, parwrite, parioctl,
127 nostop, notty, nopoll, nommap, nokqfilter,
128 };
129
130 int
131 parmatch(pdp, cfp, aux)
132 struct device *pdp;
133 struct cfdata *cfp;
134 void *aux;
135 {
136 struct intio_attach_args *ia = aux;
137
138 /* X680x0 has only one parallel port */
139 if (strcmp(ia->ia_name, "par") || cfp->cf_unit > 0)
140 return 0;
141
142 if (ia->ia_addr == INTIOCF_ADDR_DEFAULT)
143 ia->ia_addr = 0xe8c000;
144 ia->ia_size = 0x2000;
145 if (intio_map_allocate_region (pdp, ia, INTIO_MAP_TESTONLY))
146 return 0;
147 if (ia->ia_intr == INTIOCF_INTR_DEFAULT)
148 ia->ia_intr = 99;
149 #if DIAGNOSTIC
150 if (ia->ia_intr != 99)
151 return 0;
152 #endif
153
154 return 1;
155 }
156
157 void
158 parattach(pdp, dp, aux)
159 struct device *pdp, *dp;
160 void *aux;
161 {
162 register struct par_softc *sc = (struct par_softc *)dp;
163 struct intio_attach_args *ia = aux;
164 int r;
165
166 sc->sc_flags = PARF_ALIVE;
167 printf(": parallel port (write only, interrupt)\n");
168 ia->ia_size = 0x2000;
169 r = intio_map_allocate_region (pdp, ia, INTIO_MAP_ALLOCATE);
170 #ifdef DIAGNOSTIC
171 if (r)
172 panic ("IO map for PAR corruption??");
173 #endif
174 sc->sc_bst = ia->ia_bst;
175 r = bus_space_map (sc->sc_bst,
176 ia->ia_addr, ia->ia_size,
177 BUS_SPACE_MAP_SHIFTED,
178 &sc->sc_bsh);
179 #ifdef DIAGNOSTIC
180 if (r)
181 panic ("Cannot map IO space for PAR.");
182 #endif
183
184 intio_set_sicilian_intr(intio_get_sicilian_intr() &
185 ~SICILIAN_INTR_PAR);
186
187 intio_intr_establish(ia->ia_intr, "par",
188 (intio_intr_handler_t) parintr, (void*) 1);
189
190 callout_init(&sc->sc_timo_ch);
191 callout_init(&sc->sc_start_ch);
192 }
193
194 int
195 paropen(dev, flags, mode, p)
196 dev_t dev;
197 int flags, mode;
198 struct proc *p;
199 {
200 register int unit = UNIT(dev);
201 register struct par_softc *sc;
202
203 if (unit != 0)
204 return(ENXIO);
205 sc = par_cd.cd_devs[unit];
206 if (!(sc->sc_flags & PARF_ALIVE))
207 return(ENXIO);
208 if (sc->sc_flags & PARF_OPEN)
209 return(EBUSY);
210 /* X680x0 can't read */
211 if ((flags & FREAD) == FREAD)
212 return (EINVAL);
213
214 sc->sc_flags |= PARF_OPEN;
215
216 sc->sc_flags |= PARF_OWRITE;
217
218 sc->sc_burst = PAR_BURST;
219 sc->sc_timo = parmstohz(PAR_TIMO);
220 sc->sc_delay = parmstohz(PAR_DELAY);
221
222 return(0);
223 }
224
225 int
226 parclose(dev, flags, mode, p)
227 dev_t dev;
228 int flags, mode;
229 struct proc *p;
230 {
231 int unit = UNIT(dev);
232 int s;
233 struct par_softc *sc = par_cd.cd_devs[unit];
234
235 sc->sc_flags &= ~(PARF_OPEN|PARF_OWRITE);
236
237 /* don't allow interrupts any longer */
238 s = spl1();
239 intio_set_sicilian_intr(intio_get_sicilian_intr() &
240 ~SICILIAN_INTR_PAR);
241 splx(s);
242
243 return (0);
244 }
245
246 void
247 parstart(arg)
248 void *arg;
249 {
250 struct par_softc *sc = arg;
251 #ifdef DEBUG
252 if (pardebug & PDB_FOLLOW)
253 printf("parstart(%x)\n", sc->sc_dev.dv_unit);
254 #endif
255 sc->sc_flags &= ~PARF_DELAY;
256 wakeup(sc);
257 }
258
259 void
260 partimo(arg)
261 void *arg;
262 {
263 struct par_softc *sc = arg;
264 #ifdef DEBUG
265 if (pardebug & PDB_FOLLOW)
266 printf("partimo(%x)\n", sc->sc_dev.dv_unit);
267 #endif
268 sc->sc_flags &= ~(PARF_UIO|PARF_TIMO);
269 wakeup(sc);
270 }
271
272 int
273 parwrite(dev, uio, flag)
274 dev_t dev;
275 struct uio *uio;
276 int flag;
277 {
278
279 #ifdef DEBUG
280 if (pardebug & PDB_FOLLOW)
281 printf("parwrite(%x, %p)\n", dev, uio);
282 #endif
283 return (parrw(dev, uio));
284 }
285
286 int
287 parrw(dev, uio)
288 dev_t dev;
289 register struct uio *uio;
290 {
291 int unit = UNIT(dev);
292 register struct par_softc *sc = par_cd.cd_devs[unit];
293 register int s, len, cnt;
294 register char *cp;
295 int error = 0;
296 int buflen;
297 char *buf;
298
299 if (!!(sc->sc_flags & PARF_OREAD) ^ (uio->uio_rw == UIO_READ))
300 return EINVAL;
301
302 if (uio->uio_resid == 0)
303 return(0);
304
305 buflen = min(sc->sc_burst, uio->uio_resid);
306 buf = (char *)malloc(buflen, M_DEVBUF, M_WAITOK);
307 sc->sc_flags |= PARF_UIO;
308 if (sc->sc_timo > 0) {
309 sc->sc_flags |= PARF_TIMO;
310 callout_reset(&sc->sc_timo_ch, sc->sc_timo, partimo, sc);
311 }
312 while (uio->uio_resid > 0) {
313 len = min(buflen, uio->uio_resid);
314 cp = buf;
315 if (uio->uio_rw == UIO_WRITE) {
316 error = uiomove(cp, len, uio);
317 if (error)
318 break;
319 }
320 again:
321 s = spl1();
322 /*
323 * Check if we timed out during sleep or uiomove
324 */
325 (void) spllowersoftclock();
326 if ((sc->sc_flags & PARF_UIO) == 0) {
327 #ifdef DEBUG
328 if (pardebug & PDB_IO)
329 printf("parrw: uiomove/sleep timo, flags %x\n",
330 sc->sc_flags);
331 #endif
332 if (sc->sc_flags & PARF_TIMO) {
333 callout_stop(&sc->sc_timo_ch);
334 sc->sc_flags &= ~PARF_TIMO;
335 }
336 splx(s);
337 break;
338 }
339 splx(s);
340 /*
341 * Perform the operation
342 */
343 cnt = parsend(sc, cp, len);
344 if (cnt < 0) {
345 error = -cnt;
346 break;
347 }
348
349 s = splsoftclock();
350 /*
351 * Operation timeout (or non-blocking), quit now.
352 */
353 if ((sc->sc_flags & PARF_UIO) == 0) {
354 #ifdef DEBUG
355 if (pardebug & PDB_IO)
356 printf("parrw: timeout/done\n");
357 #endif
358 splx(s);
359 break;
360 }
361 /*
362 * Implement inter-read delay
363 */
364 if (sc->sc_delay > 0) {
365 sc->sc_flags |= PARF_DELAY;
366 callout_reset(&sc->sc_start_ch, sc->sc_delay,
367 parstart, sc);
368 error = tsleep(sc, PCATCH|(PZERO-1), "par-cdelay", 0);
369 if (error) {
370 splx(s);
371 break;
372 }
373 }
374 splx(s);
375 /*
376 * Must not call uiomove again til we've used all data
377 * that we already grabbed.
378 */
379 if (uio->uio_rw == UIO_WRITE && cnt != len) {
380 cp += cnt;
381 len -= cnt;
382 cnt = 0;
383 goto again;
384 }
385 }
386 s = splsoftclock();
387 if (sc->sc_flags & PARF_TIMO) {
388 callout_stop(&sc->sc_timo_ch);
389 sc->sc_flags &= ~PARF_TIMO;
390 }
391 if (sc->sc_flags & PARF_DELAY) {
392 callout_stop(&sc->sc_start_ch);
393 sc->sc_flags &= ~PARF_DELAY;
394 }
395 splx(s);
396 /*
397 * Adjust for those chars that we uiomove'ed but never wrote
398 */
399 if (uio->uio_rw == UIO_WRITE && cnt != len) {
400 uio->uio_resid += (len - cnt);
401 #ifdef DEBUG
402 if (pardebug & PDB_IO)
403 printf("parrw: short write, adjust by %d\n",
404 len-cnt);
405 #endif
406 }
407 free(buf, M_DEVBUF);
408 #ifdef DEBUG
409 if (pardebug & (PDB_FOLLOW|PDB_IO))
410 printf("parrw: return %d, resid %d\n", error, uio->uio_resid);
411 #endif
412 return (error);
413 }
414
415 int
416 parioctl(dev, cmd, data, flag, p)
417 dev_t dev;
418 u_long cmd;
419 caddr_t data;
420 int flag;
421 struct proc *p;
422 {
423 struct par_softc *sc = par_cd.cd_devs[UNIT(dev)];
424 struct parparam *pp, *upp;
425 int error = 0;
426
427 switch (cmd) {
428 case PARIOCGPARAM:
429 pp = &sc->sc_param;
430 upp = (struct parparam *)data;
431 upp->burst = pp->burst;
432 upp->timo = parhztoms(pp->timo);
433 upp->delay = parhztoms(pp->delay);
434 break;
435
436 case PARIOCSPARAM:
437 pp = &sc->sc_param;
438 upp = (struct parparam *)data;
439 if (upp->burst < PAR_BURST_MIN || upp->burst > PAR_BURST_MAX ||
440 upp->delay < PAR_DELAY_MIN || upp->delay > PAR_DELAY_MAX)
441 return(EINVAL);
442 pp->burst = upp->burst;
443 pp->timo = parmstohz(upp->timo);
444 pp->delay = parmstohz(upp->delay);
445 break;
446
447 default:
448 return(EINVAL);
449 }
450 return (error);
451 }
452
453 int
454 parhztoms(h)
455 int h;
456 {
457 extern int hz;
458 register int m = h;
459
460 if (m > 0)
461 m = m * 1000 / hz;
462 return(m);
463 }
464
465 int
466 parmstohz(m)
467 int m;
468 {
469 extern int hz;
470 register int h = m;
471
472 if (h > 0) {
473 h = h * hz / 1000;
474 if (h == 0)
475 h = 1000 / hz;
476 }
477 return(h);
478 }
479
480 /* stuff below here if for interrupt driven output of data thru
481 the parallel port. */
482
483 int partimeout_pending;
484 int parsend_pending;
485
486 void
487 parintr(arg)
488 void *arg;
489 {
490 int s, mask;
491
492 mask = (int)arg;
493 s = splclock();
494
495 intio_set_sicilian_intr(intio_get_sicilian_intr() &
496 ~SICILIAN_INTR_PAR);
497
498 #ifdef DEBUG
499 if (pardebug & PDB_INTERRUPT)
500 printf ("parintr %d(%s)\n", mask, mask ? "FLG" : "tout");
501 #endif
502 /* if invoked from timeout handler, mask will be 0,
503 * if from interrupt, it will contain the cia-icr mask,
504 * which is != 0
505 */
506 if (mask) {
507 if (partimeout_pending)
508 callout_stop(&intr_callout);
509 if (parsend_pending)
510 parsend_pending = 0;
511 }
512
513 /* either way, there won't be a timeout pending any longer */
514 partimeout_pending = 0;
515
516 wakeup(parintr);
517 splx (s);
518 }
519
520 int
521 parsendch(sc, ch)
522 struct par_softc *sc;
523 u_char ch;
524 {
525 int error = 0;
526 int s;
527
528 /* if either offline, busy or out of paper, wait for that
529 condition to clear */
530 s = spl1();
531 while (!error
532 && (parsend_pending
533 || !(intio_get_sicilian_intr() & SICILIAN_STAT_PAR)))
534 {
535 extern int hz;
536
537 /* wait a second, and try again */
538 callout_reset(&intr_callout, hz, parintr, 0);
539 partimeout_pending = 1;
540 /* this is essentially a flipflop to have us wait for the
541 first character being transmitted when trying to transmit
542 the second, etc. */
543 parsend_pending = 0;
544 /* it's quite important that a parallel putc can be
545 interrupted, given the possibility to lock a printer
546 in an offline condition.. */
547 if ((error = tsleep (parintr, PCATCH|(PZERO-1), "parsendch", 0))) {
548 #ifdef DEBUG
549 if (pardebug & PDB_INTERRUPT)
550 printf ("parsendch interrupted, error = %d\n", error);
551 #endif
552 if (partimeout_pending)
553 callout_stop(&intr_callout);
554
555 partimeout_pending = 0;
556 }
557 }
558
559 if (!error) {
560 #ifdef DEBUG
561 if (pardebug & PDB_INTERRUPT)
562 printf ("#%d", ch);
563 #endif
564 bus_space_write_1 (sc->sc_bst, sc->sc_bsh, PAR_DATA, ch);
565 DELAY(1); /* (DELAY(1) == 1us) > 0.5us */
566 bus_space_write_1 (sc->sc_bst, sc->sc_bsh, PAR_STROBE, 0);
567 intio_set_sicilian_intr (intio_get_sicilian_intr() |
568 SICILIAN_INTR_PAR);
569 DELAY(1);
570 bus_space_write_1 (sc->sc_bst, sc->sc_bsh, PAR_STROBE, 1);
571 parsend_pending = 1;
572 }
573
574 splx (s);
575
576 return error;
577 }
578
579
580 int
581 parsend(sc, buf, len)
582 struct par_softc *sc;
583 u_char *buf;
584 int len;
585 {
586 int err, orig_len = len;
587
588 for (; len; len--, buf++)
589 if ((err = parsendch (sc, *buf)))
590 return err < 0 ? -EINTR : -err;
591
592 /* either all or nothing.. */
593 return orig_len;
594 }
595