Home | History | Annotate | Line # | Download | only in dev
par.c revision 1.33
      1 /*	$NetBSD: par.c,v 1.33 2007/07/14 10:46:26 ad 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. Neither the name of the University nor the names of its contributors
     16  *    may be used to endorse or promote products derived from this software
     17  *    without specific prior written permission.
     18  *
     19  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     20  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     22  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     23  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     24  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     25  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     26  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     27  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     28  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     29  * SUCH DAMAGE.
     30  *
     31  *	@(#)ppi.c	7.3 (Berkeley) 12/16/90
     32  */
     33 
     34 /*
     35  * parallel port interface
     36  */
     37 
     38 #include <sys/cdefs.h>
     39 __KERNEL_RCSID(0, "$NetBSD: par.c,v 1.33 2007/07/14 10:46:26 ad Exp $");
     40 
     41 #include <sys/param.h>
     42 #include <sys/errno.h>
     43 #include <sys/uio.h>
     44 #include <sys/device.h>
     45 #include <sys/malloc.h>
     46 #include <sys/file.h>
     47 #include <sys/systm.h>
     48 #include <sys/callout.h>
     49 #include <sys/proc.h>
     50 #include <sys/conf.h>
     51 #include <sys/kernel.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(void *);
     88 void parstart(void *);
     89 void parintr(void *);
     90 int parrw(dev_t, struct uio *);
     91 int parhztoms(int);
     92 int parmstohz(int);
     93 int parsendch(struct par_softc *, u_char);
     94 int parsend(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(struct device *, struct cfdata *, void *);
    113 void parattach(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 static int par_attached;
    121 
    122 dev_type_open(paropen);
    123 dev_type_close(parclose);
    124 dev_type_write(parwrite);
    125 dev_type_ioctl(parioctl);
    126 
    127 const struct cdevsw par_cdevsw = {
    128 	paropen, parclose, noread, parwrite, parioctl,
    129 	nostop, notty, nopoll, nommap, nokqfilter,
    130 };
    131 
    132 int
    133 parmatch(struct device *pdp, struct cfdata *cfp, void *aux)
    134 {
    135 	struct intio_attach_args *ia = aux;
    136 
    137 	/* X680x0 has only one parallel port */
    138 	if (strcmp(ia->ia_name, "par") || par_attached)
    139 		return 0;
    140 
    141 	if (ia->ia_addr == INTIOCF_ADDR_DEFAULT)
    142 		ia->ia_addr = 0xe8c000;
    143 	ia->ia_size = 0x2000;
    144 	if (intio_map_allocate_region(pdp, ia, INTIO_MAP_TESTONLY))
    145 		return 0;
    146 	if (ia->ia_intr == INTIOCF_INTR_DEFAULT)
    147 		ia->ia_intr = 99;
    148 #if DIAGNOSTIC
    149 	if (ia->ia_intr != 99)
    150 		return 0;
    151 #endif
    152 
    153 	return 1;
    154 }
    155 
    156 void
    157 parattach(struct device *pdp, struct device *dp, void *aux)
    158 {
    159 	struct par_softc *sc = (struct par_softc *)dp;
    160 	struct intio_attach_args *ia = aux;
    161 	int r;
    162 
    163 	par_attached = 1;
    164 
    165 	sc->sc_flags = PARF_ALIVE;
    166 	printf(": parallel port (write only, interrupt)\n");
    167 	ia->ia_size = 0x2000;
    168 	r = intio_map_allocate_region(pdp, ia, INTIO_MAP_ALLOCATE);
    169 #ifdef DIAGNOSTIC
    170 	if (r)
    171 		panic("IO map for PAR corruption??");
    172 #endif
    173 	sc->sc_bst = ia->ia_bst;
    174 	r = bus_space_map(sc->sc_bst,
    175 			   ia->ia_addr, ia->ia_size,
    176 			   BUS_SPACE_MAP_SHIFTED,
    177 			   &sc->sc_bsh);
    178 #ifdef DIAGNOSTIC
    179 	if (r)
    180 		panic("Cannot map IO space for PAR.");
    181 #endif
    182 
    183 	intio_set_sicilian_intr(intio_get_sicilian_intr() &
    184 				~SICILIAN_INTR_PAR);
    185 
    186 	intio_intr_establish(ia->ia_intr, "par",
    187 			     (intio_intr_handler_t)parintr, (void *)1);
    188 
    189 	callout_init(&sc->sc_timo_ch, 0);
    190 	callout_init(&sc->sc_start_ch, 0);
    191 }
    192 
    193 int
    194 paropen(dev_t dev, int flags, int mode, struct lwp *l)
    195 {
    196 	int unit = UNIT(dev);
    197 	struct par_softc *sc;
    198 
    199 	sc = device_lookup(&par_cd, unit);
    200 	if (sc == NULL || !(sc->sc_flags & PARF_ALIVE))
    201 		return(ENXIO);
    202 	if (sc->sc_flags & PARF_OPEN)
    203 		return(EBUSY);
    204 	/* X680x0 can't read */
    205 	if ((flags & FREAD) == FREAD)
    206 		return (EINVAL);
    207 
    208 	sc->sc_flags |= PARF_OPEN;
    209 
    210 	sc->sc_flags |= PARF_OWRITE;
    211 
    212 	sc->sc_burst = PAR_BURST;
    213 	sc->sc_timo = parmstohz(PAR_TIMO);
    214 	sc->sc_delay = parmstohz(PAR_DELAY);
    215 
    216 	return(0);
    217 }
    218 
    219 int
    220 parclose(dev_t dev, int flags, int mode, struct lwp *l)
    221 {
    222 	int unit = UNIT(dev);
    223 	int s;
    224 	struct par_softc *sc = par_cd.cd_devs[unit];
    225 
    226 	sc->sc_flags &= ~(PARF_OPEN|PARF_OWRITE);
    227 
    228 	/* don't allow interrupts any longer */
    229 	s = spl1();
    230 	intio_set_sicilian_intr(intio_get_sicilian_intr() &
    231 				~SICILIAN_INTR_PAR);
    232 	splx(s);
    233 
    234 	return (0);
    235 }
    236 
    237 void
    238 parstart(void *arg)
    239 {
    240 	struct par_softc *sc = arg;
    241 #ifdef DEBUG
    242 	if (pardebug & PDB_FOLLOW)
    243 		printf("parstart(%x)\n", device_unit(&sc->sc_dev));
    244 #endif
    245 	sc->sc_flags &= ~PARF_DELAY;
    246 	wakeup(sc);
    247 }
    248 
    249 void
    250 partimo(void *arg)
    251 {
    252 	struct par_softc *sc = arg;
    253 #ifdef DEBUG
    254 	if (pardebug & PDB_FOLLOW)
    255 		printf("partimo(%x)\n", device_unit(&sc->sc_dev));
    256 #endif
    257 	sc->sc_flags &= ~(PARF_UIO|PARF_TIMO);
    258 	wakeup(sc);
    259 }
    260 
    261 int
    262 parwrite(dev_t dev, struct uio *uio, int flag)
    263 {
    264 
    265 #ifdef DEBUG
    266 	if (pardebug & PDB_FOLLOW)
    267 		printf("parwrite(%x, %p)\n", dev, uio);
    268 #endif
    269 	return (parrw(dev, uio));
    270 }
    271 
    272 int
    273 parrw(dev_t dev, struct uio *uio)
    274 {
    275 	int unit = UNIT(dev);
    276 	struct par_softc *sc = par_cd.cd_devs[unit];
    277 	int len=0xdeadbeef;	/* XXX: shutup gcc */
    278 	int s, cnt=0;
    279 	char *cp;
    280 	int error = 0;
    281 	int buflen;
    282 	char *buf;
    283 
    284 	if (!!(sc->sc_flags & PARF_OREAD) ^ (uio->uio_rw == UIO_READ))
    285 		return EINVAL;
    286 
    287 	if (uio->uio_resid == 0)
    288 		return(0);
    289 
    290 	buflen = min(sc->sc_burst, uio->uio_resid);
    291 	buf = (char *)malloc(buflen, M_DEVBUF, M_WAITOK);
    292 	sc->sc_flags |= PARF_UIO;
    293 	if (sc->sc_timo > 0) {
    294 		sc->sc_flags |= PARF_TIMO;
    295 		callout_reset(&sc->sc_timo_ch, sc->sc_timo, partimo, sc);
    296 	}
    297 	while (uio->uio_resid > 0) {
    298 		len = min(buflen, uio->uio_resid);
    299 		cp = buf;
    300 		if (uio->uio_rw == UIO_WRITE) {
    301 			error = uiomove(cp, len, uio);
    302 			if (error)
    303 				break;
    304 		}
    305 	      again:
    306 		s = splsoftclock();
    307 		/*
    308 		 * Check if we timed out during sleep or uiomove
    309 		 */
    310 		if ((sc->sc_flags & PARF_UIO) == 0) {
    311 #ifdef DEBUG
    312 			if (pardebug & PDB_IO)
    313 				printf("parrw: uiomove/sleep timo, flags %x\n",
    314 				       sc->sc_flags);
    315 #endif
    316 			if (sc->sc_flags & PARF_TIMO) {
    317 				callout_stop(&sc->sc_timo_ch);
    318 				sc->sc_flags &= ~PARF_TIMO;
    319 			}
    320 			splx(s);
    321 			break;
    322 		}
    323 		splx(s);
    324 		/*
    325 		 * Perform the operation
    326 		 */
    327 		cnt = parsend(sc, cp, len);
    328 		if (cnt < 0) {
    329 			error = -cnt;
    330 			break;
    331 		}
    332 
    333 		s = splsoftclock();
    334 		/*
    335 		 * Operation timeout (or non-blocking), quit now.
    336 		 */
    337 		if ((sc->sc_flags & PARF_UIO) == 0) {
    338 #ifdef DEBUG
    339 			if (pardebug & PDB_IO)
    340 				printf("parrw: timeout/done\n");
    341 #endif
    342 			splx(s);
    343 			break;
    344 		}
    345 		/*
    346 		 * Implement inter-read delay
    347 		 */
    348 		if (sc->sc_delay > 0) {
    349 			sc->sc_flags |= PARF_DELAY;
    350 			callout_reset(&sc->sc_start_ch, sc->sc_delay,
    351 			    parstart, sc);
    352 			error = tsleep(sc, PCATCH|(PZERO-1), "par-cdelay", 0);
    353 			if (error) {
    354 				splx(s);
    355 				break;
    356 			}
    357 		}
    358 		splx(s);
    359 		/*
    360 		 * Must not call uiomove again til we've used all data
    361 		 * that we already grabbed.
    362 		 */
    363 		if (uio->uio_rw == UIO_WRITE && cnt != len) {
    364 			cp += cnt;
    365 			len -= cnt;
    366 			cnt = 0;
    367 			goto again;
    368 		}
    369 	}
    370 	s = splsoftclock();
    371 	if (sc->sc_flags & PARF_TIMO) {
    372 		callout_stop(&sc->sc_timo_ch);
    373 		sc->sc_flags &= ~PARF_TIMO;
    374 	}
    375 	if (sc->sc_flags & PARF_DELAY)	{
    376 		callout_stop(&sc->sc_start_ch);
    377 		sc->sc_flags &= ~PARF_DELAY;
    378 	}
    379 	splx(s);
    380 	/*
    381 	 * Adjust for those chars that we uiomove'ed but never wrote
    382 	 */
    383 	/*
    384 	 * XXXjdolecek: this len usage is wrong, this will be incorrect
    385 	 * if the transfer size is longer than sc_burst
    386 	 */
    387 	if (uio->uio_rw == UIO_WRITE && cnt != len) {
    388 		uio->uio_resid += (len - cnt);
    389 #ifdef DEBUG
    390 			if (pardebug & PDB_IO)
    391 				printf("parrw: short write, adjust by %d\n",
    392 				       len-cnt);
    393 #endif
    394 	}
    395 	free(buf, M_DEVBUF);
    396 #ifdef DEBUG
    397 	if (pardebug & (PDB_FOLLOW|PDB_IO))
    398 		printf("parrw: return %d, resid %d\n", error, uio->uio_resid);
    399 #endif
    400 	return (error);
    401 }
    402 
    403 int
    404 parioctl(dev_t dev, u_long cmd, void *data, int flag, struct lwp *l)
    405 {
    406 	struct par_softc *sc = par_cd.cd_devs[UNIT(dev)];
    407 	struct parparam *pp, *upp;
    408 	int error = 0;
    409 
    410 	switch (cmd) {
    411 	case PARIOCGPARAM:
    412 		pp = &sc->sc_param;
    413 		upp = (struct parparam *)data;
    414 		upp->burst = pp->burst;
    415 		upp->timo = parhztoms(pp->timo);
    416 		upp->delay = parhztoms(pp->delay);
    417 		break;
    418 
    419 	case PARIOCSPARAM:
    420 		pp = &sc->sc_param;
    421 		upp = (struct parparam *)data;
    422 		if (upp->burst < PAR_BURST_MIN || upp->burst > PAR_BURST_MAX ||
    423 		    upp->delay < PAR_DELAY_MIN || upp->delay > PAR_DELAY_MAX)
    424 			return(EINVAL);
    425 		pp->burst = upp->burst;
    426 		pp->timo = parmstohz(upp->timo);
    427 		pp->delay = parmstohz(upp->delay);
    428 		break;
    429 
    430 	default:
    431 		return(EINVAL);
    432 	}
    433 	return (error);
    434 }
    435 
    436 int
    437 parhztoms(int h)
    438 {
    439 	int m = h;
    440 
    441 	if (m > 0)
    442 		m = m * 1000 / hz;
    443 	return(m);
    444 }
    445 
    446 int
    447 parmstohz(int m)
    448 {
    449 	int h = m;
    450 
    451 	if (h > 0) {
    452 		h = h * hz / 1000;
    453 		if (h == 0)
    454 			h = 1000 / hz;
    455 	}
    456 	return(h);
    457 }
    458 
    459 /* stuff below here if for interrupt driven output of data thru
    460    the parallel port. */
    461 
    462 int partimeout_pending;
    463 int parsend_pending;
    464 
    465 void
    466 parintr(void *arg)
    467 {
    468 	int s, mask;
    469 
    470 	mask = (int)arg;
    471 	s = splclock();
    472 
    473 	intio_set_sicilian_intr(intio_get_sicilian_intr() &
    474 				~SICILIAN_INTR_PAR);
    475 
    476 #ifdef DEBUG
    477 	if (pardebug & PDB_INTERRUPT)
    478 		printf("parintr %d(%s)\n", mask, mask ? "FLG" : "tout");
    479 #endif
    480 	/* if invoked from timeout handler, mask will be 0,
    481 	 * if from interrupt, it will contain the cia-icr mask,
    482 	 * which is != 0
    483 	 */
    484 	if (mask) {
    485 		if (partimeout_pending)
    486 			callout_stop(&intr_callout);
    487 		if (parsend_pending)
    488 			parsend_pending = 0;
    489 	}
    490 
    491 	/* either way, there won't be a timeout pending any longer */
    492 	partimeout_pending = 0;
    493 
    494 	wakeup(parintr);
    495 	splx(s);
    496 }
    497 
    498 int
    499 parsendch(struct par_softc *sc, u_char ch)
    500 {
    501 	int error = 0;
    502 	int s;
    503 
    504 	/* if either offline, busy or out of paper, wait for that
    505 	   condition to clear */
    506 	s = spl1();
    507 	while (!error
    508 	       && (parsend_pending
    509 		   || !(intio_get_sicilian_intr() & SICILIAN_STAT_PAR)))
    510 	{
    511 		/* wait a second, and try again */
    512 		callout_reset(&intr_callout, hz, parintr, 0);
    513 		partimeout_pending = 1;
    514 		/* this is essentially a flipflop to have us wait for the
    515 		   first character being transmitted when trying to transmit
    516 		   the second, etc. */
    517 		parsend_pending = 0;
    518 		/* it's quite important that a parallel putc can be
    519 		   interrupted, given the possibility to lock a printer
    520 		   in an offline condition.. */
    521 		if ((error = tsleep(parintr, PCATCH|(PZERO-1), "parsendch", 0))) {
    522 #ifdef DEBUG
    523 			if (pardebug & PDB_INTERRUPT)
    524 				printf("parsendch interrupted, error = %d\n", error);
    525 #endif
    526 			if (partimeout_pending)
    527 				callout_stop(&intr_callout);
    528 
    529 			partimeout_pending = 0;
    530 		}
    531 	}
    532 
    533 	if (!error) {
    534 #ifdef DEBUG
    535 		if (pardebug & PDB_INTERRUPT)
    536 			printf("#%d", ch);
    537 #endif
    538 		bus_space_write_1(sc->sc_bst, sc->sc_bsh, PAR_DATA, ch);
    539 		DELAY(1);	/* (DELAY(1) == 1us) > 0.5us */
    540 		bus_space_write_1(sc->sc_bst, sc->sc_bsh, PAR_STROBE, 0);
    541 		intio_set_sicilian_intr(intio_get_sicilian_intr() |
    542 					 SICILIAN_INTR_PAR);
    543 		DELAY(1);
    544 		bus_space_write_1(sc->sc_bst, sc->sc_bsh, PAR_STROBE, 1);
    545 		parsend_pending = 1;
    546 	}
    547 
    548 	splx(s);
    549 
    550 	return error;
    551 }
    552 
    553 
    554 int
    555 parsend(struct par_softc *sc, u_char *buf, int len)
    556 {
    557 	int err, orig_len = len;
    558 
    559 	for (; len; len--, buf++)
    560 		if ((err = parsendch(sc, *buf)))
    561 			return err < 0 ? -EINTR : -err;
    562 
    563 	/* either all or nothing.. */
    564 	return orig_len;
    565 }
    566