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