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