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