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