1 /* $NetBSD: par.c,v 1.16 1996/12/23 09:10:28 veego 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 #include <sys/param.h> 46 #include <sys/errno.h> 47 #include <sys/uio.h> 48 #include <sys/device.h> 49 #include <sys/malloc.h> 50 #include <sys/file.h> 51 #include <sys/systm.h> 52 #include <sys/proc.h> 53 54 #include <amiga/amiga/device.h> 55 #include <amiga/amiga/cia.h> 56 #include <amiga/dev/parioctl.h> 57 58 #include <sys/conf.h> 59 #include <machine/conf.h> 60 61 struct par_softc { 62 int sc_flags; 63 struct parparam sc_param; 64 #define sc_burst sc_param.burst 65 #define sc_timo sc_param.timo 66 #define sc_delay sc_param.delay 67 } *par_softcp; 68 69 #define getparsp(x) (x > 0 ? NULL : par_softcp) 70 71 /* sc_flags values */ 72 #define PARF_ALIVE 0x01 73 #define PARF_OPEN 0x02 74 #define PARF_UIO 0x04 75 #define PARF_TIMO 0x08 76 #define PARF_DELAY 0x10 77 #define PARF_OREAD 0x40 78 #define PARF_OWRITE 0x80 79 80 #define UNIT(x) minor(x) 81 82 #ifdef DEBUG 83 int pardebug = 0; 84 #define PDB_FOLLOW 0x01 85 #define PDB_IO 0x02 86 #define PDB_INTERRUPT 0x04 87 #define PDB_NOCHECK 0x80 88 #endif 89 90 int parrw __P((dev_t, struct uio *)); 91 int parhztoms __P((int)); 92 int parmstohz __P((int)); 93 int parsend __P((u_char *, int)); 94 int parreceive __P((u_char *, int)); 95 int parsendch __P((u_char)); 96 97 void partimo __P((void *)); 98 void parstart __P((void *)); 99 void parintr __P((void *)); 100 101 void parattach __P((struct device *, struct device *, void *)); 102 int parmatch __P((struct device *, struct cfdata *, void *)); 103 104 struct cfattach par_ca = { 105 sizeof(struct device), parmatch, parattach 106 }; 107 108 struct cfdriver par_cd = { 109 NULL, "par", DV_DULL, NULL, 0 110 }; 111 112 /*ARGSUSED*/ 113 int 114 parmatch(pdp, cfp, auxp) 115 struct device *pdp; 116 struct cfdata *cfp; 117 void *auxp; 118 { 119 120 if (matchname((char *)auxp, "par") && cfp->cf_unit == 0) 121 return(1); 122 return(0); 123 } 124 125 void 126 parattach(pdp, dp, auxp) 127 struct device *pdp, *dp; 128 void *auxp; 129 { 130 par_softcp = (struct par_softc *)dp; 131 132 #ifdef DEBUG 133 if ((pardebug & PDB_NOCHECK) == 0) 134 #endif 135 par_softcp->sc_flags = PARF_ALIVE; 136 printf("\n"); 137 } 138 139 int 140 paropen(dev, flags, mode, p) 141 dev_t dev; 142 int flags; 143 int mode; 144 struct proc *p; 145 { 146 int unit = UNIT(dev); 147 struct par_softc *sc = getparsp(unit); 148 149 if (unit >= NPAR || (sc->sc_flags & PARF_ALIVE) == 0) 150 return(ENXIO); 151 #ifdef DEBUG 152 if (pardebug & PDB_FOLLOW) { 153 printf("paropen(%x, %x): flags %x, ", 154 dev, flags, sc->sc_flags); 155 printf ("port = $%x\n", ((ciab.pra ^ CIAB_PRA_SEL) 156 & (CIAB_PRA_SEL|CIAB_PRA_BUSY|CIAB_PRA_POUT))); 157 } 158 #endif 159 if (sc->sc_flags & PARF_OPEN) 160 return(EBUSY); 161 /* can either read or write, but not both */ 162 if ((flags & (FREAD|FWRITE)) == (FREAD|FWRITE)) 163 return EINVAL; 164 165 sc->sc_flags |= PARF_OPEN; 166 167 if (flags & FREAD) 168 sc->sc_flags |= PARF_OREAD; 169 else 170 sc->sc_flags |= PARF_OWRITE; 171 172 sc->sc_burst = PAR_BURST; 173 sc->sc_timo = parmstohz(PAR_TIMO); 174 sc->sc_delay = parmstohz(PAR_DELAY); 175 /* enable interrupts for CIAA-FLG */ 176 ciaa.icr = CIA_ICR_IR_SC | CIA_ICR_FLG; 177 return(0); 178 } 179 180 int 181 parclose(dev, flags, mode, p) 182 dev_t dev; 183 int flags; 184 int mode; 185 struct proc *p; 186 { 187 int unit = UNIT(dev); 188 struct par_softc *sc = getparsp(unit); 189 190 #ifdef DEBUG 191 if (pardebug & PDB_FOLLOW) 192 printf("parclose(%x, %x): flags %x\n", 193 dev, flags, sc->sc_flags); 194 #endif 195 sc->sc_flags &= ~(PARF_OPEN|PARF_OREAD|PARF_OWRITE); 196 /* don't allow interrupts for CIAA-FLG any longer */ 197 ciaa.icr = CIA_ICR_FLG; 198 return(0); 199 } 200 201 void 202 parstart(arg) 203 void *arg; 204 { 205 struct par_softc *sc; 206 int unit; 207 208 unit = (int)arg; 209 sc = getparsp(unit); 210 #ifdef DEBUG 211 if (pardebug & PDB_FOLLOW) 212 printf("parstart(%x)\n", unit); 213 #endif 214 sc->sc_flags &= ~PARF_DELAY; 215 wakeup(sc); 216 } 217 218 void 219 partimo(arg) 220 void *arg; 221 { 222 struct par_softc *sc; 223 int unit; 224 225 unit = (int) arg; 226 sc = getparsp(unit); 227 #ifdef DEBUG 228 if (pardebug & PDB_FOLLOW) 229 printf("partimo(%x)\n", unit); 230 #endif 231 sc->sc_flags &= ~(PARF_UIO|PARF_TIMO); 232 wakeup(sc); 233 } 234 235 int 236 parread(dev, uio, flags) 237 dev_t dev; 238 struct uio *uio; 239 int flags; 240 { 241 242 #ifdef DEBUG 243 if (pardebug & PDB_FOLLOW) 244 printf("parread(%x, %p)\n", dev, uio); 245 #endif 246 return (parrw(dev, uio)); 247 } 248 249 250 int 251 parwrite(dev, uio, flags) 252 dev_t dev; 253 struct uio *uio; 254 int flags; 255 { 256 257 #ifdef DEBUG 258 if (pardebug & PDB_FOLLOW) 259 printf("parwrite(%x, %p)\n", dev, uio); 260 #endif 261 return (parrw(dev, uio)); 262 } 263 264 265 int 266 parrw(dev, uio) 267 dev_t dev; 268 register struct uio *uio; 269 { 270 int unit = UNIT(dev); 271 register struct par_softc *sc = getparsp(unit); 272 register int s, len, cnt; 273 register char *cp; 274 int error = 0, gotdata = 0; 275 int buflen; 276 char *buf; 277 278 len = 0; 279 cnt = 0; 280 if (!!(sc->sc_flags & PARF_OREAD) ^ (uio->uio_rw == UIO_READ)) 281 return EINVAL; 282 283 if (uio->uio_resid == 0) 284 return(0); 285 286 #ifdef DEBUG 287 if (pardebug & (PDB_FOLLOW|PDB_IO)) 288 printf("parrw(%x, %p, %c): burst %d, timo %d, resid %x\n", 289 dev, uio, uio->uio_rw == UIO_READ ? 'R' : 'W', 290 sc->sc_burst, sc->sc_timo, uio->uio_resid); 291 #endif 292 buflen = min(sc->sc_burst, uio->uio_resid); 293 buf = (char *)malloc(buflen, M_DEVBUF, M_WAITOK); 294 sc->sc_flags |= PARF_UIO; 295 if (sc->sc_timo > 0) 296 { 297 sc->sc_flags |= PARF_TIMO; 298 timeout(partimo, (void *)unit, sc->sc_timo); 299 } 300 while (uio->uio_resid > 0) 301 { 302 len = min(buflen, uio->uio_resid); 303 cp = buf; 304 if (uio->uio_rw == UIO_WRITE) 305 { 306 error = uiomove(cp, len, uio); 307 if (error) 308 break; 309 } 310 again: 311 s = splbio(); 312 #if 0 313 if ((sc->sc_flags & PARF_UIO) && hpibreq(&sc->sc_dq) == 0) 314 sleep(sc, PRIBIO+1); 315 #endif 316 /* 317 * Check if we timed out during sleep or uiomove 318 */ 319 (void) splsoftclock(); 320 if ((sc->sc_flags & PARF_UIO) == 0) 321 { 322 #ifdef DEBUG 323 if (pardebug & PDB_IO) 324 printf("parrw: uiomove/sleep timo, flags %x\n", 325 sc->sc_flags); 326 #endif 327 if (sc->sc_flags & PARF_TIMO) 328 { 329 untimeout(partimo, (void *)unit); 330 sc->sc_flags &= ~PARF_TIMO; 331 } 332 splx(s); 333 break; 334 } 335 splx(s); 336 /* 337 * Perform the operation 338 */ 339 if (uio->uio_rw == UIO_WRITE) 340 cnt = parsend (cp, len); 341 else 342 cnt = parreceive (cp, len); 343 344 if (cnt < 0) 345 { 346 error = -cnt; 347 break; 348 } 349 350 s = splbio(); 351 #if 0 352 hpibfree(&sc->sc_dq); 353 #endif 354 #ifdef DEBUG 355 if (pardebug & PDB_IO) 356 printf("parrw: %s(%p, %d) -> %d\n", 357 uio->uio_rw == UIO_READ ? "recv" : "send", cp, len, cnt); 358 #endif 359 splx(s); 360 if (uio->uio_rw == UIO_READ) 361 { 362 if (cnt) 363 { 364 error = uiomove(cp, cnt, uio); 365 if (error) 366 break; 367 gotdata++; 368 } 369 /* 370 * Didn't get anything this time, but did in the past. 371 * Consider us done. 372 */ 373 else if (gotdata) 374 break; 375 } 376 s = splsoftclock(); 377 /* 378 * Operation timeout (or non-blocking), quit now. 379 */ 380 if ((sc->sc_flags & PARF_UIO) == 0) 381 { 382 #ifdef DEBUG 383 if (pardebug & PDB_IO) 384 printf("parrw: timeout/done\n"); 385 #endif 386 splx(s); 387 break; 388 } 389 /* 390 * Implement inter-read delay 391 */ 392 if (sc->sc_delay > 0) 393 { 394 sc->sc_flags |= PARF_DELAY; 395 timeout(parstart, (void *)unit, sc->sc_delay); 396 error = tsleep(sc, PCATCH | (PZERO - 1), "par-cdelay", 0); 397 if (error) 398 { 399 splx(s); 400 break; 401 } 402 } 403 splx(s); 404 /* 405 * Must not call uiomove again til we've used all data 406 * that we already grabbed. 407 */ 408 if (uio->uio_rw == UIO_WRITE && cnt != len) 409 { 410 cp += cnt; 411 len -= cnt; 412 cnt = 0; 413 goto again; 414 } 415 } 416 s = splsoftclock(); 417 if (sc->sc_flags & PARF_TIMO) 418 { 419 untimeout(partimo, (void *)unit); 420 sc->sc_flags &= ~PARF_TIMO; 421 } 422 if (sc->sc_flags & PARF_DELAY) 423 { 424 untimeout(parstart, (void *)unit); 425 sc->sc_flags &= ~PARF_DELAY; 426 } 427 splx(s); 428 /* 429 * Adjust for those chars that we uiomove'ed but never wrote 430 */ 431 if (uio->uio_rw == UIO_WRITE && cnt != len) 432 { 433 uio->uio_resid += (len - cnt); 434 #ifdef DEBUG 435 if (pardebug & PDB_IO) 436 printf("parrw: short write, adjust by %d\n", 437 len-cnt); 438 #endif 439 } 440 free(buf, M_DEVBUF); 441 #ifdef DEBUG 442 if (pardebug & (PDB_FOLLOW|PDB_IO)) 443 printf("parrw: return %d, resid %d\n", error, uio->uio_resid); 444 #endif 445 return (error); 446 } 447 448 int 449 parioctl(dev, cmd, data, flag, p) 450 dev_t dev; 451 u_long cmd; 452 caddr_t data; 453 int flag; 454 struct proc *p; 455 { 456 struct par_softc *sc = getparsp(UNIT(dev)); 457 struct parparam *pp, *upp; 458 int error = 0; 459 460 switch (cmd) 461 { 462 case PARIOCGPARAM: 463 pp = &sc->sc_param; 464 upp = (struct parparam *)data; 465 upp->burst = pp->burst; 466 upp->timo = parhztoms(pp->timo); 467 upp->delay = parhztoms(pp->delay); 468 break; 469 470 case PARIOCSPARAM: 471 pp = &sc->sc_param; 472 upp = (struct parparam *)data; 473 if (upp->burst < PAR_BURST_MIN || upp->burst > PAR_BURST_MAX || 474 upp->delay < PAR_DELAY_MIN || upp->delay > PAR_DELAY_MAX) 475 return(EINVAL); 476 pp->burst = upp->burst; 477 pp->timo = parmstohz(upp->timo); 478 pp->delay = parmstohz(upp->delay); 479 break; 480 481 default: 482 return(EINVAL); 483 } 484 return (error); 485 } 486 487 int 488 parhztoms(h) 489 int h; 490 { 491 extern int hz; 492 register int m = h; 493 494 if (m > 0) 495 m = m * 1000 / hz; 496 return(m); 497 } 498 499 int 500 parmstohz(m) 501 int m; 502 { 503 extern int hz; 504 register int h = m; 505 506 if (h > 0) { 507 h = h * hz / 1000; 508 if (h == 0) 509 h = 1000 / hz; 510 } 511 return(h); 512 } 513 514 /* stuff below here if for interrupt driven output of data thru 515 the parallel port. */ 516 517 int partimeout_pending; 518 int parsend_pending; 519 520 void 521 parintr(arg) 522 void *arg; 523 { 524 int s, mask; 525 526 mask = (int)arg; 527 s = splclock(); 528 529 #ifdef DEBUG 530 if (pardebug & PDB_INTERRUPT) 531 printf("parintr %s\n", mask ? "FLG" : "tout"); 532 #endif 533 /* 534 * if invoked from timeout handler, mask will be 0, 535 * if from interrupt, it will contain the cia-icr mask, 536 * which is != 0 537 */ 538 if (mask) { 539 if (partimeout_pending) 540 untimeout(parintr, 0); 541 if (parsend_pending) 542 parsend_pending = 0; 543 } 544 545 /* either way, there won't be a timeout pending any longer */ 546 partimeout_pending = 0; 547 548 wakeup(parintr); 549 splx(s); 550 } 551 552 int 553 parsendch (ch) 554 u_char ch; 555 { 556 int error = 0; 557 int s; 558 559 /* if either offline, busy or out of paper, wait for that 560 condition to clear */ 561 s = splclock(); 562 while (!error 563 && (parsend_pending 564 || ((ciab.pra ^ CIAB_PRA_SEL) 565 & (CIAB_PRA_SEL|CIAB_PRA_BUSY|CIAB_PRA_POUT)))) 566 { 567 extern int hz; 568 569 #ifdef DEBUG 570 if (pardebug & PDB_INTERRUPT) 571 printf ("parsendch, port = $%x\n", 572 ((ciab.pra ^ CIAB_PRA_SEL) 573 & (CIAB_PRA_SEL|CIAB_PRA_BUSY|CIAB_PRA_POUT))); 574 #endif 575 /* wait a second, and try again */ 576 timeout(parintr, 0, hz); 577 partimeout_pending = 1; 578 /* this is essentially a flipflop to have us wait for the 579 first character being transmitted when trying to transmit 580 the second, etc. */ 581 parsend_pending = 0; 582 /* it's quite important that a parallel putc can be 583 interrupted, given the possibility to lock a printer 584 in an offline condition.. */ 585 if ((error = tsleep(parintr, PCATCH | (PZERO - 1), "parsendch", 0)) > 0) 586 { 587 #ifdef DEBUG 588 if (pardebug & PDB_INTERRUPT) 589 printf ("parsendch interrupted, error = %d\n", error); 590 #endif 591 if (partimeout_pending) 592 untimeout(parintr, 0); 593 594 partimeout_pending = 0; 595 } 596 } 597 598 if (! error) 599 { 600 #ifdef DEBUG 601 if (pardebug & PDB_INTERRUPT) 602 printf ("#%d", ch); 603 #endif 604 ciaa.prb = ch; 605 parsend_pending = 1; 606 } 607 608 splx (s); 609 610 return error; 611 } 612 613 614 int 615 parsend (buf, len) 616 u_char *buf; 617 int len; 618 { 619 int err, orig_len = len; 620 621 /* make sure I/O lines are setup right for output */ 622 623 /* control lines set to input */ 624 ciab.ddra &= ~(CIAB_PRA_SEL|CIAB_PRA_POUT|CIAB_PRA_BUSY); 625 /* data lines to output */ 626 ciaa.ddrb = 0xff; 627 628 for (; len; len--, buf++) 629 if ((err = parsendch (*buf)) != 0) 630 return err < 0 ? -EINTR : -err; 631 632 /* either all or nothing.. */ 633 return orig_len; 634 } 635 636 637 638 int 639 parreceive (buf, len) 640 u_char *buf; 641 int len; 642 { 643 /* oh deary me, something's gotta be left to be implemented 644 later... */ 645 return 0; 646 } 647 648 649 #endif 650