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