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