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