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