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