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